From c0019bce6bb570ea72c85774e21996ecfce4a417 Mon Sep 17 00:00:00 2001 From: Valeriy Ponomaryov Date: Tue, 24 Feb 2015 15:45:15 +0200 Subject: [PATCH] Add snapshot gigabytes quota Manila has used single gigabytes quota for shares and snapshots. Config opt 'no_snapshot_gb_quota' is set to False by default, that has been used for enabling/disabling of snapshot gigabytes quota considerations. Add separate snapshot gigabyte quota and remove opt 'no_snapshot_gb_quota' that is not needed anymore. To be able to set infinite quota for snapshot gigabytes, just set value for new config option 'quota_snapshot_gigabytes' to '-1'. Change-Id: I43cb95ff3d0d3e6191f520b52edb67a0a44e9c2c Implements BP add-snapshot-gb-quota --- .../tempest/api/share/admin/test_quotas.py | 73 +++++++++++++++-- .../api/share/admin/test_quotas_negative.py | 24 ++++++ .../tempest/tempest/api/share/test_quotas.py | 3 + .../services/share/json/shares_client.py | 6 +- manila/api/contrib/used_limits.py | 1 + manila/api/views/limits.py | 1 + manila/common/config.py | 4 +- manila/db/sqlalchemy/api.py | 20 +++-- manila/exception.py | 7 +- manila/quota.py | 8 +- manila/share/api.py | 9 ++- manila/share/manager.py | 7 +- manila/tests/share/test_api.py | 2 +- manila/tests/test_quota.py | 80 ++++++++++++------- 14 files changed, 180 insertions(+), 65 deletions(-) diff --git a/contrib/tempest/tempest/api/share/admin/test_quotas.py b/contrib/tempest/tempest/api/share/admin/test_quotas.py index 2ea0d321..b0cbbe6b 100644 --- a/contrib/tempest/tempest/api/share/admin/test_quotas.py +++ b/contrib/tempest/tempest/api/share/admin/test_quotas.py @@ -40,6 +40,7 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest): resp, quotas = self.shares_client.default_quotas(self.tenant["id"]) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertGreater(int(quotas["gigabytes"]), -2) + self.assertGreater(int(quotas["snapshot_gigabytes"]), -2) self.assertGreater(int(quotas["shares"]), -2) self.assertGreater(int(quotas["snapshots"]), -2) self.assertGreater(int(quotas["share_networks"]), -2) @@ -49,6 +50,7 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest): resp, quotas = self.shares_client.show_quotas(self.tenant["id"]) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertGreater(int(quotas["gigabytes"]), -2) + self.assertGreater(int(quotas["snapshot_gigabytes"]), -2) self.assertGreater(int(quotas["shares"]), -2) self.assertGreater(int(quotas["snapshots"]), -2) self.assertGreater(int(quotas["share_networks"]), -2) @@ -59,6 +61,7 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest): self.user["id"]) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertGreater(int(quotas["gigabytes"]), -2) + self.assertGreater(int(quotas["snapshot_gigabytes"]), -2) self.assertGreater(int(quotas["shares"]), -2) self.assertGreater(int(quotas["snapshots"]), -2) self.assertGreater(int(quotas["share_networks"]), -2) @@ -149,6 +152,25 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest): self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertEqual(int(updated["gigabytes"]), gigabytes) + @test.attr(type=["gate", "smoke", ]) + def test_update_tenant_quota_snapshot_gigabytes(self): + client = self.get_client_with_isolated_creds() + + # get current quotas + resp, custom = client.show_quotas(client.creds["tenant"]["id"]) + self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + + # make quotas for update + snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2 + + # set new quota for shares + resp, updated = client.update_quotas( + client.creds["tenant"]["id"], + snapshot_gigabytes=snapshot_gigabytes) + self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + self.assertEqual( + int(updated["snapshot_gigabytes"]), snapshot_gigabytes) + @test.attr(type=["gate", "smoke", ]) def test_update_user_quota_gigabytes(self): client = self.get_client_with_isolated_creds() @@ -169,6 +191,27 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest): self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertEqual(int(updated["gigabytes"]), gigabytes) + @test.attr(type=["gate", "smoke", ]) + def test_update_user_quota_snapshot_gigabytes(self): + client = self.get_client_with_isolated_creds() + + # get current quotas + resp, custom = client.show_quotas(client.creds["tenant"]["id"], + client.creds["user"]["id"]) + + self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + + # make quotas for update + snapshot_gigabytes = int(custom["snapshot_gigabytes"]) - 1 + + # set new quota for shares + resp, updated = client.update_quotas( + client.creds["tenant"]["id"], client.creds["user"]["id"], + snapshot_gigabytes=snapshot_gigabytes) + self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + self.assertEqual( + int(updated["snapshot_gigabytes"]), snapshot_gigabytes) + @test.attr(type=["gate", "smoke", ]) def test_update_tenant_quota_share_networks(self): client = self.get_client_with_isolated_creds() @@ -217,18 +260,23 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest): shares = int(custom["shares"]) + 2 snapshots = int(custom["snapshots"]) + 2 gigabytes = int(custom["gigabytes"]) + 2 + snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2 share_networks = int(custom["share_networks"]) + 2 # set new quota - resp, updated = client.update_quotas(client.creds["tenant"]["id"], - shares=shares, - snapshots=snapshots, - gigabytes=gigabytes, - share_networks=share_networks) + resp, updated = client.update_quotas( + client.creds["tenant"]["id"], + shares=shares, + snapshots=snapshots, + gigabytes=gigabytes, + snapshot_gigabytes=snapshot_gigabytes, + share_networks=share_networks) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertEqual(int(updated["shares"]), shares) self.assertEqual(int(updated["snapshots"]), snapshots) self.assertEqual(int(updated["gigabytes"]), gigabytes) + self.assertEqual( + int(updated["snapshot_gigabytes"]), snapshot_gigabytes) self.assertEqual(int(updated["share_networks"]), share_networks) # reset customized quotas @@ -281,6 +329,13 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest): gigabytes=-1) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + @test.attr(type=["gate", "smoke", ]) + def test_unlimited_quota_for_snapshot_gigabytes(self): + client = self.get_client_with_isolated_creds() + resp, __ = client.update_quotas(client.creds["tenant"]["id"], + snapshot_gigabytes=-1) + self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + @test.attr(type=["gate", "smoke", ]) def test_unlimited_user_quota_for_gigabytes(self): client = self.get_client_with_isolated_creds() @@ -289,6 +344,14 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest): gigabytes=-1) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + @test.attr(type=["gate", "smoke", ]) + def test_unlimited_user_quota_for_snapshot_gigabytes(self): + client = self.get_client_with_isolated_creds() + resp, __ = client.update_quotas(client.creds["tenant"]["id"], + client.creds["user"]["id"], + snapshot_gigabytes=-1) + self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) + @test.attr(type=["gate", "smoke", ]) def test_unlimited_quota_for_share_networks(self): client = self.get_client_with_isolated_creds() diff --git a/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py b/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py index 3cc5ee8f..f47cd634 100644 --- a/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py +++ b/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py @@ -79,6 +79,15 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest): client.creds["tenant"]["id"], gigabytes=-2) + @test.attr(type=["gate", "smoke", "negative"]) + def test_update_snapshot_gigabytes_quota_with_wrong_data(self): + # -1 is acceptable value as unlimited + client = self.get_client_with_isolated_creds() + self.assertRaises(exceptions.BadRequest, + client.update_quotas, + client.creds["tenant"]["id"], + snapshot_gigabytes=-2) + @test.attr(type=["gate", "smoke", "negative"]) def test_update_share_networks_quota_with_wrong_data(self): # -1 is acceptable value as unlimited @@ -145,6 +154,21 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest): client.creds["user"]["id"], gigabytes=bigger_value) + @test.attr(type=["gate", "smoke", "negative"]) + def test_try_set_user_quota_snap_gigabytes_bigger_than_tenant_quota(self): + client = self.get_client_with_isolated_creds() + + # get current quotas for tenant + __, tenant_quotas = client.show_quotas(client.creds["tenant"]["id"]) + + # try set user quota for snapshot gigabytes bigger than tenant quota + bigger_value = int(tenant_quotas["snapshot_gigabytes"]) + 2 + self.assertRaises(exceptions.BadRequest, + client.update_quotas, + client.creds["tenant"]["id"], + client.creds["user"]["id"], + snapshot_gigabytes=bigger_value) + @test.attr(type=["gate", "smoke", "negative"]) def test_try_set_user_quota_share_networks_bigger_than_tenant_quota(self): client = self.get_client_with_isolated_creds() diff --git a/contrib/tempest/tempest/api/share/test_quotas.py b/contrib/tempest/tempest/api/share/test_quotas.py index 6a1e6ddb..845c247f 100644 --- a/contrib/tempest/tempest/api/share/test_quotas.py +++ b/contrib/tempest/tempest/api/share/test_quotas.py @@ -35,6 +35,7 @@ class SharesQuotasTest(base.BaseSharesTest): resp, quotas = self.shares_client.default_quotas(self.tenant["id"]) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertGreater(int(quotas["gigabytes"]), -2) + self.assertGreater(int(quotas["snapshot_gigabytes"]), -2) self.assertGreater(int(quotas["shares"]), -2) self.assertGreater(int(quotas["snapshots"]), -2) self.assertGreater(int(quotas["share_networks"]), -2) @@ -44,6 +45,7 @@ class SharesQuotasTest(base.BaseSharesTest): resp, quotas = self.shares_client.show_quotas(self.tenant["id"]) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertGreater(int(quotas["gigabytes"]), -2) + self.assertGreater(int(quotas["snapshot_gigabytes"]), -2) self.assertGreater(int(quotas["shares"]), -2) self.assertGreater(int(quotas["snapshots"]), -2) self.assertGreater(int(quotas["share_networks"]), -2) @@ -54,6 +56,7 @@ class SharesQuotasTest(base.BaseSharesTest): self.user["id"]) self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) self.assertGreater(int(quotas["gigabytes"]), -2) + self.assertGreater(int(quotas["snapshot_gigabytes"]), -2) self.assertGreater(int(quotas["shares"]), -2) self.assertGreater(int(quotas["snapshots"]), -2) self.assertGreater(int(quotas["share_networks"]), -2) diff --git a/contrib/tempest/tempest/services/share/json/shares_client.py b/contrib/tempest/tempest/services/share/json/shares_client.py index 8d03315e..aa91da8d 100644 --- a/contrib/tempest/tempest/services/share/json/shares_client.py +++ b/contrib/tempest/tempest/services/share/json/shares_client.py @@ -245,8 +245,8 @@ class SharesClient(service_client.ServiceClient): return self.delete(uri) def update_quotas(self, tenant_id, user_id=None, shares=None, - snapshots=None, gigabytes=None, share_networks=None, - force=True): + snapshots=None, gigabytes=None, snapshot_gigabytes=None, + share_networks=None, force=True): uri = "os-quota-sets/%s" % tenant_id if user_id is not None: uri += "?user_id=%s" % user_id @@ -260,6 +260,8 @@ class SharesClient(service_client.ServiceClient): put_body["snapshots"] = snapshots if gigabytes is not None: put_body["gigabytes"] = gigabytes + if snapshot_gigabytes is not None: + put_body["snapshot_gigabytes"] = snapshot_gigabytes if share_networks is not None: put_body["share_networks"] = share_networks put_body = json.dumps({"quota_set": put_body}) diff --git a/manila/api/contrib/used_limits.py b/manila/api/contrib/used_limits.py index 16224dc5..dbdad642 100644 --- a/manila/api/contrib/used_limits.py +++ b/manila/api/contrib/used_limits.py @@ -39,6 +39,7 @@ class UsedLimitsController(wsgi.Controller): 'totalShareSnapshotsUsed': 'snapshots', 'totalShareNetworksUsed': 'share_networks', 'totalShareGigabytesUsed': 'gigabytes', + 'totalSnapshotGigabytesUsed': 'snapshot_gigabytes', } used_limits = {} diff --git a/manila/api/views/limits.py b/manila/api/views/limits.py index 591dc450..536baf36 100644 --- a/manila/api/views/limits.py +++ b/manila/api/views/limits.py @@ -44,6 +44,7 @@ class ViewBuilder(object): """ limit_names = { "gigabytes": ["maxTotalShareGigabytes"], + "snapshot_gigabytes": ["maxTotalSnapshotGigabytes"], "shares": ["maxTotalShares"], "snapshots": ["maxTotalShareSnapshots"], "share_networks": ["maxTotalShareNetworks"], diff --git a/manila/common/config.py b/manila/common/config.py index 209bf757..4b2f4c91 100644 --- a/manila/common/config.py +++ b/manila/common/config.py @@ -174,9 +174,7 @@ global_opts = [ help="Specify list of protocols to be allowed for share " "creation. Available values are '%s'" % six.text_type( constants.SUPPORTED_SHARE_PROTOCOLS)), - cfg.BoolOpt('no_snapshot_gb_quota', - default=False, - help='Whether snapshots count against Gigabyte quota.'), ] +] CONF.register_opts(global_opts) diff --git a/manila/db/sqlalchemy/api.py b/manila/db/sqlalchemy/api.py index 650487ba..acd2cf9c 100644 --- a/manila/db/sqlalchemy/api.py +++ b/manila/db/sqlalchemy/api.py @@ -263,18 +263,15 @@ def _sync_snapshots(context, project_id, user_id, session): def _sync_gigabytes(context, project_id, user_id, session): - (_junk, share_gigs) = share_data_get_for_project(context, - project_id, - user_id, - session=session) - if CONF.no_snapshot_gb_quota: - return {'gigabytes': share_gigs} + _junk, share_gigs = share_data_get_for_project( + context, project_id, user_id, session=session) + return dict(gigabytes=share_gigs) - (_junk, snap_gigs) = snapshot_data_get_for_project(context, - project_id, - user_id, - session=session) - return {'gigabytes': share_gigs + snap_gigs} + +def _sync_snapshot_gigabytes(context, project_id, user_id, session): + _junk, snapshot_gigs = snapshot_data_get_for_project( + context, project_id, user_id, session=session) + return dict(snapshot_gigabytes=snapshot_gigs) def _sync_share_networks(context, project_id, user_id, session): @@ -289,6 +286,7 @@ QUOTA_SYNC_FUNCTIONS = { '_sync_shares': _sync_shares, '_sync_snapshots': _sync_snapshots, '_sync_gigabytes': _sync_gigabytes, + '_sync_snapshot_gigabytes': _sync_snapshot_gigabytes, '_sync_share_networks': _sync_share_networks, } diff --git a/manila/exception.py b/manila/exception.py index 6f57f2e1..19599885 100644 --- a/manila/exception.py +++ b/manila/exception.py @@ -306,8 +306,11 @@ class QuotaError(ManilaException): class ShareSizeExceedsAvailableQuota(QuotaError): - message = _("Requested share or snapshot exceeds " - "allowed gigabytes quota.") + message = _("Requested share exceeds allowed gigabytes quota.") + + +class SnapshotSizeExceedsAvailableQuota(QuotaError): + message = _("Requested snapshot exceeds allowed gigabytes quota.") class ShareLimitExceeded(QuotaError): diff --git a/manila/quota.py b/manila/quota.py index d61ce939..eeee7140 100644 --- a/manila/quota.py +++ b/manila/quota.py @@ -39,8 +39,10 @@ quota_opts = [ help='Number of share snapshots allowed per project.'), cfg.IntOpt('quota_gigabytes', default=1000, - help='Number of share gigabytes (snapshots are also included) ' - 'allowed per project.'), + help='Number of share gigabytes allowed per project.'), + cfg.IntOpt('quota_snapshot_gigabytes', + default=1000, + help='Number of snapshot gigabytes allowed per project.'), cfg.IntOpt('quota_share_networks', default=10, help='Number of share-networks allowed per project.'), @@ -1076,6 +1078,8 @@ resources = [ ReservableResource('shares', '_sync_shares', 'quota_shares'), ReservableResource('snapshots', '_sync_snapshots', 'quota_snapshots'), ReservableResource('gigabytes', '_sync_gigabytes', 'quota_gigabytes'), + ReservableResource('snapshot_gigabytes', '_sync_snapshot_gigabytes', + 'quota_snapshot_gigabytes'), ReservableResource('share_networks', '_sync_share_networks', 'quota_share_networks'), ] diff --git a/manila/share/api.py b/manila/share/api.py index 0ba8551b..86f394f9 100644 --- a/manila/share/api.py +++ b/manila/share/api.py @@ -272,7 +272,8 @@ class API(base.Base): size = share['size'] try: - reservations = QUOTAS.reserve(context, snapshots=1, gigabytes=size) + reservations = QUOTAS.reserve( + context, snapshots=1, snapshot_gigabytes=size) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] @@ -281,15 +282,15 @@ class API(base.Base): def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) - if 'gigabytes' in overs: + if 'snapshot_gigabytes' in overs: msg = _LW("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG snapshot (%(d_consumed)dG of " "%(d_quota)dG already consumed)") LOG.warn(msg, {'s_pid': context.project_id, 's_size': size, 'd_consumed': _consumed('gigabytes'), - 'd_quota': quotas['gigabytes']}) - raise exception.ShareSizeExceedsAvailableQuota() + 'd_quota': quotas['snapshot_gigabytes']}) + raise exception.SnapshotSizeExceedsAvailableQuota() elif 'snapshots' in overs: msg = _LW("Quota exceeded for %(s_pid)s, tried to create " "snapshot (%(d_consumed)d snapshots " diff --git a/manila/share/manager.py b/manila/share/manager.py index c8d4f347..c1a4b82a 100644 --- a/manila/share/manager.py +++ b/manila/share/manager.py @@ -399,10 +399,9 @@ class ShareManager(manager.SchedulerDependentManager): else: self.db.share_snapshot_destroy(context, snapshot_id) try: - reservations = QUOTAS.reserve(context, - project_id=project_id, - snapshots=-1, - gigabytes=-snapshot_ref['size']) + reservations = QUOTAS.reserve( + context, project_id=project_id, snapshots=-1, + snapshot_gigabytes=-snapshot_ref['size']) except Exception: reservations = None LOG.exception(_LE("Failed to update usages deleting snapshot")) diff --git a/manila/tests/share/test_api.py b/manila/tests/share/test_api.py index 31c41e20..3139373e 100644 --- a/manila/tests/share/test_api.py +++ b/manila/tests/share/test_api.py @@ -498,7 +498,7 @@ class ShareAPITestCase(test.TestCase): share_api.policy.check_policy.assert_called_once_with( self.context, 'share', 'create_snapshot', share) quota.QUOTAS.reserve.assert_called_once_with( - self.context, snapshots=1, gigabytes=1) + self.context, snapshots=1, snapshot_gigabytes=1) quota.QUOTAS.commit.assert_called_once_with( self.context, 'reservation') db_driver.share_snapshot_create.assert_called_once_with( diff --git a/manila/tests/test_quota.py b/manila/tests/test_quota.py index 4f0bfe6e..717ef25a 100644 --- a/manila/tests/test_quota.py +++ b/manila/tests/test_quota.py @@ -616,20 +616,17 @@ class DbQuotaDriverTestCase(test.TestCase): expected_all_context = { "shares": {"limit": 10, "in_use": 2, "reserved": 0, }, "gigabytes": {"limit": 50, "in_use": 10, "reserved": 0, }, - "snapshots": {"limit": 10, "in_use": 0, "reserved": 0, }, + "snapshot_gigabytes": {"limit": 50, "in_use": 20, "reserved": 0, }, + "snapshots": {"limit": 10, "in_use": 4, "reserved": 0, }, "share_networks": {"limit": 10, "in_use": 0, "reserved": 0, }, } def setUp(self): super(DbQuotaDriverTestCase, self).setUp() - - self.flags(quota_shares=10, - quota_snapshots=10, - quota_gigabytes=1000, - reservation_expire=86400, - until_refresh=0, - max_age=0, - ) + self.flags( + quota_shares=10, quota_snapshots=10, quota_gigabytes=1000, + quota_snapshot_gigabytes=1000, reservation_expire=86400, + until_refresh=0, max_age=0) self.driver = quota.DbQuotaDriver() @@ -649,17 +646,18 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": 10, "gigabytes": 1000, + "snapshot_gigabytes": 1000, "snapshots": 10, "share_networks": 10, } - self.assertEqual(result, expected) + self.assertEqual(expected, result) def _stub_quota_class_get_all_by_name(self): # Stub out quota_class_get_all_by_name def fake_qcgabn(context, quota_class): self.calls.append('quota_class_get_all_by_name') self.assertEqual(quota_class, 'test_class') - return dict(gigabytes=500, shares=10, ) + return dict(gigabytes=500, shares=10, snapshot_gigabytes=50) self.mock_object(db, 'quota_class_get_all_by_name', fake_qcgabn) def test_get_class_quotas(self): @@ -671,10 +669,11 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": 10, "gigabytes": 500, + "snapshot_gigabytes": 50, "snapshots": 10, "share_networks": 10, } - self.assertEqual(result, expected) + self.assertEqual(expected, result) def test_get_class_quotas_no_defaults(self): self._stub_quota_class_get_all_by_name() @@ -682,27 +681,35 @@ class DbQuotaDriverTestCase(test.TestCase): 'test_class', False) self.assertEqual(self.calls, ['quota_class_get_all_by_name']) - self.assertEqual(result, dict(shares=10, - gigabytes=500)) + self.assertEqual( + dict(shares=10, gigabytes=500, snapshot_gigabytes=50), result) def _stub_get_by_project_and_user(self): def fake_qgabpu(context, project_id, user_id): self.calls.append('quota_get_all_by_project_and_user') self.assertEqual(project_id, 'test_project') self.assertEqual(user_id, 'fake_user') - return dict(shares=10, gigabytes=50, reserved=0) + return dict( + shares=10, gigabytes=50, snapshots=10, snapshot_gigabytes=50, + reserved=0) def fake_qgabp(context, project_id): self.calls.append('quota_get_all_by_project') self.assertEqual(project_id, 'test_project') - return dict(shares=10, gigabytes=50, reserved=0) + return dict( + shares=10, gigabytes=50, snapshots=10, snapshot_gigabytes=50, + reserved=0) def fake_qugabpu(context, project_id, user_id): self.calls.append('quota_usage_get_all_by_project_and_user') self.assertEqual(project_id, 'test_project') self.assertEqual(user_id, 'fake_user') - return dict(shares=dict(in_use=2, reserved=0), - gigabytes=dict(in_use=10, reserved=0), ) + return dict( + shares=dict(in_use=2, reserved=0), + gigabytes=dict(in_use=10, reserved=0), + snapshots=dict(in_use=4, reserved=0), + snapshot_gigabytes=dict(in_use=20, reserved=0), + ) self.mock_object(db, 'quota_get_all_by_project_and_user', fake_qgabpu) self.mock_object(db, 'quota_get_all_by_project', fake_qgabp) @@ -723,19 +730,23 @@ class DbQuotaDriverTestCase(test.TestCase): 'quota_usage_get_all_by_project_and_user', 'quota_class_get_all_by_name', ]) - self.assertEqual(result, self.expected_all_context) + self.assertEqual(self.expected_all_context, result) def _stub_get_by_project(self): def fake_qgabp(context, project_id): self.calls.append('quota_get_all_by_project') self.assertEqual(project_id, 'test_project') - return dict(shares=10, gigabytes=50, reserved=0) + return dict( + shares=10, gigabytes=50, snapshot_gigabytes=50, reserved=0) def fake_qugabp(context, project_id): self.calls.append('quota_usage_get_all_by_project') self.assertEqual(project_id, 'test_project') - return dict(shares=dict(in_use=2, reserved=0), - gigabytes=dict(in_use=10, reserved=0), ) + return dict( + shares=dict(in_use=2, reserved=0), + snapshots=dict(in_use=4, reserved=0), + snapshot_gigabytes=dict(in_use=20, reserved=0), + gigabytes=dict(in_use=10, reserved=0)) self.mock_object(db, 'quota_get_all_by_project', fake_qgabp) self.mock_object(db, 'quota_usage_get_all_by_project', fake_qugabp) @@ -751,7 +762,7 @@ class DbQuotaDriverTestCase(test.TestCase): self.assertEqual(self.calls, ['quota_get_all_by_project', 'quota_usage_get_all_by_project', 'quota_class_get_all_by_name', ]) - self.assertEqual(result, self.expected_all_context) + self.assertEqual(self.expected_all_context, result) def test_get_project_quotas_with_remains(self): self._stub_get_by_project() @@ -772,7 +783,7 @@ class DbQuotaDriverTestCase(test.TestCase): 'quota_get_all_by_project', 'quota_usage_get_all_by_project_and_user', ]) - self.assertEqual(result, self.expected_all_context) + self.assertEqual(self.expected_all_context, result) def test_get_project_quotas_alt_context_no_class(self): self._stub_get_by_project() @@ -782,7 +793,7 @@ class DbQuotaDriverTestCase(test.TestCase): self.assertEqual(self.calls, ['quota_get_all_by_project', 'quota_usage_get_all_by_project', ]) - self.assertEqual(result, self.expected_all_context) + self.assertEqual(self.expected_all_context, result) def test_get_user_quotas_alt_context_with_class(self): self._stub_get_by_project_and_user() @@ -797,7 +808,7 @@ class DbQuotaDriverTestCase(test.TestCase): 'quota_usage_get_all_by_project_and_user', 'quota_class_get_all_by_name', ]) - self.assertEqual(result, self.expected_all_context) + self.assertEqual(self.expected_all_context, result) def test_get_project_quotas_alt_context_with_class(self): self._stub_get_by_project() @@ -808,7 +819,7 @@ class DbQuotaDriverTestCase(test.TestCase): self.assertEqual(self.calls, ['quota_get_all_by_project', 'quota_usage_get_all_by_project', 'quota_class_get_all_by_name', ]) - self.assertEqual(result, self.expected_all_context) + self.assertEqual(self.expected_all_context, result) def test_get_user_quotas_no_defaults(self): self._stub_get_by_project_and_user() @@ -826,8 +837,10 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": {"limit": 10, "in_use": 2, "reserved": 0, }, "gigabytes": {"limit": 50, "in_use": 10, "reserved": 0, }, + "snapshot_gigabytes": {"limit": 50, "in_use": 20, "reserved": 0, }, + "snapshots": {"limit": 10, "in_use": 4, "reserved": 0, }, } - self.assertEqual(result, expected) + self.assertEqual(expected, result) def test_get_project_quotas_no_defaults(self): self._stub_get_by_project() @@ -841,8 +854,9 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": {"limit": 10, "in_use": 2, "reserved": 0, }, "gigabytes": {"limit": 50, "in_use": 10, "reserved": 0, }, + "snapshot_gigabytes": {"limit": 50, "in_use": 20, "reserved": 0, }, } - self.assertEqual(result, expected) + self.assertEqual(expected, result) def test_get_user_quotas_no_usages(self): self._stub_get_by_project_and_user() @@ -858,10 +872,11 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": {"limit": 10, }, "gigabytes": {"limit": 50, }, + "snapshot_gigabytes": {"limit": 50, }, "snapshots": {"limit": 10, }, "share_networks": {"limit": 10, }, } - self.assertEqual(result, expected) + self.assertEqual(result, expected, result) def test_get_project_quotas_no_usages(self): self._stub_get_by_project() @@ -874,10 +889,11 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": {"limit": 10, }, "gigabytes": {"limit": 50, }, + "snapshot_gigabytes": {"limit": 50, }, "snapshots": {"limit": 10, }, "share_networks": {"limit": 10, }, } - self.assertEqual(result, expected) + self.assertEqual(expected, result) def _stub_get_settable_quotas(self): def fake_get_project_quotas(context, resources, project_id, @@ -928,6 +944,7 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": {"minimum": 0, "maximum": 12, }, "gigabytes": {"minimum": 0, "maximum": 1000, }, + "snapshot_gigabytes": {"minimum": 0, "maximum": 1000, }, "snapshots": {"minimum": 0, "maximum": 10, }, "share_networks": {"minimum": 0, "maximum": 10, }, } @@ -945,6 +962,7 @@ class DbQuotaDriverTestCase(test.TestCase): expected = { "shares": {"minimum": 0, "maximum": -1, }, "gigabytes": {"minimum": 0, "maximum": -1, }, + "snapshot_gigabytes": {"minimum": 0, "maximum": -1, }, "snapshots": {"minimum": 0, "maximum": -1, }, "share_networks": {"minimum": 0, "maximum": -1, }, }