def test_reservation_rollback(self): reservations = _quota_reserve(self.ctxt, 'project1') expected = { 'project_id': 'project1', 'volumes': { 'reserved': 1, 'in_use': 0 }, 'gigabytes': { 'reserved': 2, 'in_use': 0 }, } self.assertEqual( expected, db.quota_usage_get_all_by_project(self.ctxt, 'project1')) db.reservation_get(self.ctxt, reservations[0]) db.reservation_rollback(self.ctxt, reservations, 'project1') self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, reservations[0]) expected = { 'project_id': 'project1', 'volumes': { 'reserved': 0, 'in_use': 0 }, 'gigabytes': { 'reserved': 0, 'in_use': 0 }, } self.assertEqual( expected, db.quota_usage_get_all_by_project(self.ctxt, 'project1'))
def test_transfer_accept_with_snapshots(self): 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=fake.VOLUME_TYPE_ID, updated_at=self.updated_at) utils.create_volume_type(self.ctxt.elevated(), id=fake.VOLUME_TYPE_ID, name="test_type") utils.create_snapshot(self.ctxt, volume.id, status='available') with mock.patch('cinder.volume.volume_utils.notify_about_volume_usage' ) as mock_notify: transfer = tx_api.create(self.ctxt, volume.id, 'Description') 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) # The notify_about_volume_usage is called twice at create(). self.assertEqual(2, mock_notify.call_count) # Get volume and snapshot quota before accept self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID usages = db.quota_usage_get_all_by_project(self.ctxt, self.ctxt.project_id) self.assertEqual(0, usages.get('volumes', {}).get('in_use', 0)) self.assertEqual(0, usages.get('snapshots', {}).get('in_use', 0)) with mock.patch('cinder.volume.volume_utils.notify_about_volume_usage' ) as mock_notify: tx_api.accept(self.ctxt, transfer['id'], transfer['auth_key']) 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) # The notify_about_volume_usage is called twice at accept(). self.assertEqual(2, mock_notify.call_count) volume = objects.Volume.get_by_id(self.ctxt, volume.id) self.assertEqual(fake.PROJECT2_ID, volume.project_id) self.assertEqual(fake.USER2_ID, volume.user_id) # Get volume and snapshot quota after accept self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID usages = db.quota_usage_get_all_by_project(self.ctxt, self.ctxt.project_id) self.assertEqual(1, usages.get('volumes', {}).get('in_use', 0)) self.assertEqual(1, usages.get('snapshots', {}).get('in_use', 0))
def test_reservation_rollback(self): reservations = _quota_reserve(self.ctxt, "project1") expected = { "project_id": "project1", "volumes": {"reserved": 1, "in_use": 0}, "gigabytes": {"reserved": 2, "in_use": 0}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(self.ctxt, "project1")) db.reservation_rollback(self.ctxt, reservations, "project1") expected = { "project_id": "project1", "volumes": {"reserved": 0, "in_use": 0}, "gigabytes": {"reserved": 0, "in_use": 0}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(self.ctxt, "project1"))
def test_quota_usage_get_all_by_project(self): reservations = _quota_reserve(self.ctxt, 'p1') expected = {'project_id': 'p1', 'volumes': {'in_use': 0, 'reserved': 1}, 'gigabytes': {'in_use': 0, 'reserved': 2}} self.assertEqual(expected, db.quota_usage_get_all_by_project( self.ctxt, 'p1'))
def test_quota_destroy_all_by_project(self): reservations = _quota_reserve(self.ctxt, "project1") db.quota_destroy_all_by_project(self.ctxt, "project1") self.assertEqual(db.quota_get_all_by_project(self.ctxt, "project1"), {"project_id": "project1"}) self.assertEqual(db.quota_usage_get_all_by_project(self.ctxt, "project1"), {"project_id": "project1"}) for r in reservations: self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, r)
def get_project_quotas(self, context, resources, project_id, quota_class=None, defaults=True, usages=True): """ Given a list of resources, retrieve the quotas for the given project. :param context: The request context, for access checks. :param resources: A dictionary of the registered resources. :param project_id: The ID of the project to return quotas for. :param quota_class: If project_id != context.project_id, the quota class cannot be determined. This parameter allows it to be specified. It will be ignored if project_id == context.project_id. :param defaults: If True, the quota class value (or the default value, if there is no value from the quota class) will be reported if there is no specific value for the resource. :param usages: If True, the current in_use and reserved counts will also be returned. """ quotas = {} project_quotas = db.quota_get_all_by_project(context, project_id) if usages: project_usages = db.quota_usage_get_all_by_project(context, project_id) # Get the quotas for the appropriate class. If the project ID # matches the one in the context, we use the quota_class from # the context, otherwise, we use the provided quota_class (if # any) if project_id == context.project_id: quota_class = context.quota_class if quota_class: class_quotas = db.quota_class_get_all_by_name(context, quota_class) else: class_quotas = {} for resource in resources.values(): # Omit default/quota class values if not defaults and resource.name not in project_quotas: continue quotas[resource.name] = dict( limit=project_quotas.get(resource.name, class_quotas.get(resource.name, resource.default)), ) # Include usages if desired. This is optional because one # internal consumer of this interface wants to access the # usages directly from inside a transaction. if usages: usage = project_usages.get(resource.name, {}) quotas[resource.name].update( in_use=usage.get('in_use', 0), reserved=usage.get('reserved', 0), ) return quotas
def test_reservation_commit(self): reservations = _quota_reserve(self.ctxt, "project1") expected = { "project_id": "project1", "volumes": {"reserved": 1, "in_use": 0}, "gigabytes": {"reserved": 2, "in_use": 0}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(self.ctxt, "project1")) db.reservation_get(self.ctxt, reservations[0]) db.reservation_commit(self.ctxt, reservations, "project1") self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, reservations[0]) expected = { "project_id": "project1", "volumes": {"reserved": 0, "in_use": 1}, "gigabytes": {"reserved": 0, "in_use": 2}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(self.ctxt, "project1"))
def test_quota_usage_get_all_by_project(self): _quota_reserve(self.ctxt, "p1") expected = { "project_id": "p1", "volumes": {"in_use": 0, "reserved": 1}, "gigabytes": {"in_use": 0, "reserved": 2}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(self.ctxt, "p1"))
def test_quota_destroy_all_by_project(self): reservations = _quota_reserve(self.ctxt, 'project1') db.quota_destroy_all_by_project(self.ctxt, 'project1') self.assertEqual(db.quota_get_all_by_project(self.ctxt, 'project1'), {'project_id': 'project1'}) self.assertEqual( db.quota_usage_get_all_by_project(self.ctxt, 'project1'), {'project_id': 'project1'}) for r in reservations: self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, r)
def _commit_quota_reservation(self): # Create simple quota and quota usage. ctxt = context.get_admin_context() res = test_db_api._quota_reserve(ctxt, 'foo') db.reservation_commit(ctxt, res, 'foo') expected = {'project_id': 'foo', 'volumes': {'reserved': 0, 'in_use': 1}, 'gigabytes': {'reserved': 0, 'in_use': 2}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(ctxt, 'foo'))
def _commit_quota_reservation(self): # Create simple quota and quota usage. ctxt = context.get_admin_context() res = test_db_api._quota_reserve(ctxt, fake.PROJECT_ID) db.reservation_commit(ctxt, res, fake.PROJECT_ID) expected = { "project_id": fake.PROJECT_ID, "volumes": {"reserved": 0, "in_use": 1}, "gigabytes": {"reserved": 0, "in_use": 2}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(ctxt, fake.PROJECT_ID))
def test_reservation_expire(self): self.values["expire"] = datetime.datetime.utcnow() + datetime.timedelta(days=1) _quota_reserve(self.ctxt, "project1") db.reservation_expire(self.ctxt) expected = { "project_id": "project1", "gigabytes": {"reserved": 0, "in_use": 0}, "volumes": {"reserved": 0, "in_use": 0}, } self.assertEqual(expected, db.quota_usage_get_all_by_project(self.ctxt, "project1"))
def test_quota_reserve(self): reservations = _quota_reserve(self.ctxt, "project1") self.assertEqual(len(reservations), 2) quota_usage = db.quota_usage_get_all_by_project(self.ctxt, "project1") self.assertEqual( { "project_id": "project1", "gigabytes": {"reserved": 2, "in_use": 0}, "volumes": {"reserved": 1, "in_use": 0}, }, quota_usage, )
def test_reservation_commit(self): reservations = _quota_reserve(self.ctxt, 'project1') expected = { 'project_id': 'project1', 'res0': { 'reserved': 0, 'in_use': 0 }, 'res1': { 'reserved': 1, 'in_use': 1 }, 'res2': { 'reserved': 2, 'in_use': 2 } } self.assertEqual( expected, db.quota_usage_get_all_by_project(self.ctxt, 'project1')) db.reservation_get(self.ctxt, reservations[0]) db.reservation_commit(self.ctxt, reservations, 'project1') self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, reservations[0]) expected = { 'project_id': 'project1', 'res0': { 'reserved': 0, 'in_use': 0 }, 'res1': { 'reserved': 0, 'in_use': 2 }, 'res2': { 'reserved': 0, 'in_use': 4 } } self.assertEqual( expected, db.quota_usage_get_all_by_project(self.ctxt, 'project1'))
def test_transfer_accept_with_snapshots(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, volume_type_id=fake.VOLUME_TYPE_ID, updated_at=self.updated_at) utils.create_volume_type(self.ctxt.elevated(), id=fake.VOLUME_TYPE_ID, name="test_type") utils.create_snapshot(self.ctxt, volume.id, status='available') transfer = tx_api.create(self.ctxt, volume.id, 'Description') # Get volume and snapshot quota before accept self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID usages = db.quota_usage_get_all_by_project(self.ctxt, self.ctxt.project_id) self.assertEqual(0, usages.get('volumes', {}).get('in_use', 0)) self.assertEqual(0, usages.get('snapshots', {}).get('in_use', 0)) tx_api.accept(self.ctxt, transfer['id'], transfer['auth_key']) volume = objects.Volume.get_by_id(self.ctxt, volume.id) self.assertEqual(fake.PROJECT2_ID, volume.project_id) self.assertEqual(fake.USER2_ID, volume.user_id) 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) # The notify_about_volume_usage is called twice at create(), # and twice at accept(). self.assertEqual(4, mock_notify.call_count) # Get volume and snapshot quota after accept self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID usages = db.quota_usage_get_all_by_project(self.ctxt, self.ctxt.project_id) self.assertEqual(1, usages.get('volumes', {}).get('in_use', 0)) self.assertEqual(1, usages.get('snapshots', {}).get('in_use', 0))
def test_reservation_expire(self): self.values['expire'] = datetime.datetime.utcnow() + \ datetime.timedelta(days=1) reservations = _quota_reserve(self.ctxt, 'project1') db.reservation_expire(self.ctxt) expected = {'project_id': 'project1', 'gigabytes': {'reserved': 0, 'in_use': 0}, 'volumes': {'reserved': 0, 'in_use': 0}} self.assertEqual(expected, db.quota_usage_get_all_by_project( self.ctxt, 'project1'))
def test_reservation_commit(self): reservations = _quota_reserve(self.ctxt, 'project1') expected = {'project_id': 'project1', 'volumes': {'reserved': 1, 'in_use': 0}, 'gigabytes': {'reserved': 2, 'in_use': 0}, } self.assertEqual(expected, db.quota_usage_get_all_by_project( self.ctxt, 'project1')) db.reservation_get(self.ctxt, reservations[0]) db.reservation_commit(self.ctxt, reservations, 'project1') self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, reservations[0]) expected = {'project_id': 'project1', 'volumes': {'reserved': 0, 'in_use': 1}, 'gigabytes': {'reserved': 0, 'in_use': 2}, } self.assertEqual(expected, db.quota_usage_get_all_by_project( self.ctxt, 'project1'))
def test_reservation_rollback(self): reservations = _quota_reserve(self.ctxt, 'project1') expected = {'project_id': 'project1', 'res0': {'reserved': 0, 'in_use': 0}, 'res1': {'reserved': 1, 'in_use': 1}, 'res2': {'reserved': 2, 'in_use': 2}} self.assertEqual(expected, db.quota_usage_get_all_by_project( self.ctxt, 'project1')) db.reservation_get(self.ctxt, reservations[0]) db.reservation_rollback(self.ctxt, reservations, 'project1') self.assertRaises(exception.ReservationNotFound, db.reservation_get, self.ctxt, reservations[0]) expected = {'project_id': 'project1', 'res0': {'reserved': 0, 'in_use': 0}, 'res1': {'reserved': 0, 'in_use': 1}, 'res2': {'reserved': 0, 'in_use': 2}} self.assertEqual(expected, db.quota_usage_get_all_by_project( self.ctxt, 'project1'))
def get_project_quotas(self, context, resources, project_id, quota_class=None, defaults=True, usages=True, parent_project_id=None): """Given a list of resources, retrieve the quotas for the given project. :param context: The request context, for access checks. :param resources: A dictionary of the registered resources. :param project_id: The ID of the project to return quotas for. :param quota_class: If project_id != context.project_id, the quota class cannot be determined. This parameter allows it to be specified. It will be ignored if project_id == context.project_id. :param defaults: If True, the quota class value (or the default value, if there is no value from the quota class) will be reported if there is no specific value for the resource. :param usages: If True, the current in_use and reserved counts will also be returned. :param parent_project_id: The id of the current project's parent, if any. """ quotas = {} project_quotas = db.quota_get_all_by_project(context, project_id) if usages: project_usages = db.quota_usage_get_all_by_project(context, project_id) # Get the quotas for the appropriate class. If the project ID # matches the one in the context, we use the quota_class from # the context, otherwise, we use the provided quota_class (if # any) if project_id == context.project_id: quota_class = context.quota_class if quota_class: class_quotas = db.quota_class_get_all_by_name(context, quota_class) else: class_quotas = {} default_quotas = self.get_defaults(context, resources, parent_project_id=parent_project_id) for resource in resources.values(): # Omit default/quota class values if not defaults and resource.name not in project_quotas: continue quotas[resource.name] = dict( limit=project_quotas.get( resource.name, class_quotas.get(resource.name, default_quotas[resource.name])), ) # Include usages if desired. This is optional because one # internal consumer of this interface wants to access the # usages directly from inside a transaction. if usages: usage = project_usages.get(resource.name, {}) quotas[resource.name].update( in_use=usage.get('in_use', 0), reserved=usage.get('reserved', 0), ) return quotas
def test_quota_destroy_all_by_project(self): _quota_reserve(self.ctxt, "project1") db.quota_destroy_all_by_project(self.ctxt, "project1") self.assertEqual(db.quota_get_all_by_project(self.ctxt, "project1"), {"project_id": "project1"}) self.assertEqual(db.quota_usage_get_all_by_project(self.ctxt, "project1"), {"project_id": "project1"})