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
This commit is contained in:
parent
98a6c6621b
commit
c0019bce6b
@ -40,6 +40,7 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
|||||||
resp, quotas = self.shares_client.default_quotas(self.tenant["id"])
|
resp, quotas = self.shares_client.default_quotas(self.tenant["id"])
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||||
|
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||||
self.assertGreater(int(quotas["shares"]), -2)
|
self.assertGreater(int(quotas["shares"]), -2)
|
||||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||||
self.assertGreater(int(quotas["share_networks"]), -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"])
|
resp, quotas = self.shares_client.show_quotas(self.tenant["id"])
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||||
|
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||||
self.assertGreater(int(quotas["shares"]), -2)
|
self.assertGreater(int(quotas["shares"]), -2)
|
||||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||||
@ -59,6 +61,7 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
|||||||
self.user["id"])
|
self.user["id"])
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||||
|
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||||
self.assertGreater(int(quotas["shares"]), -2)
|
self.assertGreater(int(quotas["shares"]), -2)
|
||||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||||
self.assertGreater(int(quotas["share_networks"]), -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.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertEqual(int(updated["gigabytes"]), gigabytes)
|
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", ])
|
@test.attr(type=["gate", "smoke", ])
|
||||||
def test_update_user_quota_gigabytes(self):
|
def test_update_user_quota_gigabytes(self):
|
||||||
client = self.get_client_with_isolated_creds()
|
client = self.get_client_with_isolated_creds()
|
||||||
@ -169,6 +191,27 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
|||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertEqual(int(updated["gigabytes"]), gigabytes)
|
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", ])
|
@test.attr(type=["gate", "smoke", ])
|
||||||
def test_update_tenant_quota_share_networks(self):
|
def test_update_tenant_quota_share_networks(self):
|
||||||
client = self.get_client_with_isolated_creds()
|
client = self.get_client_with_isolated_creds()
|
||||||
@ -217,18 +260,23 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
|||||||
shares = int(custom["shares"]) + 2
|
shares = int(custom["shares"]) + 2
|
||||||
snapshots = int(custom["snapshots"]) + 2
|
snapshots = int(custom["snapshots"]) + 2
|
||||||
gigabytes = int(custom["gigabytes"]) + 2
|
gigabytes = int(custom["gigabytes"]) + 2
|
||||||
|
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
|
||||||
share_networks = int(custom["share_networks"]) + 2
|
share_networks = int(custom["share_networks"]) + 2
|
||||||
|
|
||||||
# set new quota
|
# set new quota
|
||||||
resp, updated = client.update_quotas(client.creds["tenant"]["id"],
|
resp, updated = client.update_quotas(
|
||||||
shares=shares,
|
client.creds["tenant"]["id"],
|
||||||
snapshots=snapshots,
|
shares=shares,
|
||||||
gigabytes=gigabytes,
|
snapshots=snapshots,
|
||||||
share_networks=share_networks)
|
gigabytes=gigabytes,
|
||||||
|
snapshot_gigabytes=snapshot_gigabytes,
|
||||||
|
share_networks=share_networks)
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertEqual(int(updated["shares"]), shares)
|
self.assertEqual(int(updated["shares"]), shares)
|
||||||
self.assertEqual(int(updated["snapshots"]), snapshots)
|
self.assertEqual(int(updated["snapshots"]), snapshots)
|
||||||
self.assertEqual(int(updated["gigabytes"]), gigabytes)
|
self.assertEqual(int(updated["gigabytes"]), gigabytes)
|
||||||
|
self.assertEqual(
|
||||||
|
int(updated["snapshot_gigabytes"]), snapshot_gigabytes)
|
||||||
self.assertEqual(int(updated["share_networks"]), share_networks)
|
self.assertEqual(int(updated["share_networks"]), share_networks)
|
||||||
|
|
||||||
# reset customized quotas
|
# reset customized quotas
|
||||||
@ -281,6 +329,13 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
|||||||
gigabytes=-1)
|
gigabytes=-1)
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
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", ])
|
@test.attr(type=["gate", "smoke", ])
|
||||||
def test_unlimited_user_quota_for_gigabytes(self):
|
def test_unlimited_user_quota_for_gigabytes(self):
|
||||||
client = self.get_client_with_isolated_creds()
|
client = self.get_client_with_isolated_creds()
|
||||||
@ -289,6 +344,14 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
|||||||
gigabytes=-1)
|
gigabytes=-1)
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
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", ])
|
@test.attr(type=["gate", "smoke", ])
|
||||||
def test_unlimited_quota_for_share_networks(self):
|
def test_unlimited_quota_for_share_networks(self):
|
||||||
client = self.get_client_with_isolated_creds()
|
client = self.get_client_with_isolated_creds()
|
||||||
|
@ -79,6 +79,15 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
|
|||||||
client.creds["tenant"]["id"],
|
client.creds["tenant"]["id"],
|
||||||
gigabytes=-2)
|
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"])
|
@test.attr(type=["gate", "smoke", "negative"])
|
||||||
def test_update_share_networks_quota_with_wrong_data(self):
|
def test_update_share_networks_quota_with_wrong_data(self):
|
||||||
# -1 is acceptable value as unlimited
|
# -1 is acceptable value as unlimited
|
||||||
@ -145,6 +154,21 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
|
|||||||
client.creds["user"]["id"],
|
client.creds["user"]["id"],
|
||||||
gigabytes=bigger_value)
|
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"])
|
@test.attr(type=["gate", "smoke", "negative"])
|
||||||
def test_try_set_user_quota_share_networks_bigger_than_tenant_quota(self):
|
def test_try_set_user_quota_share_networks_bigger_than_tenant_quota(self):
|
||||||
client = self.get_client_with_isolated_creds()
|
client = self.get_client_with_isolated_creds()
|
||||||
|
@ -35,6 +35,7 @@ class SharesQuotasTest(base.BaseSharesTest):
|
|||||||
resp, quotas = self.shares_client.default_quotas(self.tenant["id"])
|
resp, quotas = self.shares_client.default_quotas(self.tenant["id"])
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||||
|
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||||
self.assertGreater(int(quotas["shares"]), -2)
|
self.assertGreater(int(quotas["shares"]), -2)
|
||||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||||
self.assertGreater(int(quotas["share_networks"]), -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"])
|
resp, quotas = self.shares_client.show_quotas(self.tenant["id"])
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||||
|
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||||
self.assertGreater(int(quotas["shares"]), -2)
|
self.assertGreater(int(quotas["shares"]), -2)
|
||||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||||
@ -54,6 +56,7 @@ class SharesQuotasTest(base.BaseSharesTest):
|
|||||||
self.user["id"])
|
self.user["id"])
|
||||||
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
self.assertIn(int(resp["status"]), self.HTTP_SUCCESS)
|
||||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||||
|
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||||
self.assertGreater(int(quotas["shares"]), -2)
|
self.assertGreater(int(quotas["shares"]), -2)
|
||||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||||
|
@ -245,8 +245,8 @@ class SharesClient(service_client.ServiceClient):
|
|||||||
return self.delete(uri)
|
return self.delete(uri)
|
||||||
|
|
||||||
def update_quotas(self, tenant_id, user_id=None, shares=None,
|
def update_quotas(self, tenant_id, user_id=None, shares=None,
|
||||||
snapshots=None, gigabytes=None, share_networks=None,
|
snapshots=None, gigabytes=None, snapshot_gigabytes=None,
|
||||||
force=True):
|
share_networks=None, force=True):
|
||||||
uri = "os-quota-sets/%s" % tenant_id
|
uri = "os-quota-sets/%s" % tenant_id
|
||||||
if user_id is not None:
|
if user_id is not None:
|
||||||
uri += "?user_id=%s" % user_id
|
uri += "?user_id=%s" % user_id
|
||||||
@ -260,6 +260,8 @@ class SharesClient(service_client.ServiceClient):
|
|||||||
put_body["snapshots"] = snapshots
|
put_body["snapshots"] = snapshots
|
||||||
if gigabytes is not None:
|
if gigabytes is not None:
|
||||||
put_body["gigabytes"] = gigabytes
|
put_body["gigabytes"] = gigabytes
|
||||||
|
if snapshot_gigabytes is not None:
|
||||||
|
put_body["snapshot_gigabytes"] = snapshot_gigabytes
|
||||||
if share_networks is not None:
|
if share_networks is not None:
|
||||||
put_body["share_networks"] = share_networks
|
put_body["share_networks"] = share_networks
|
||||||
put_body = json.dumps({"quota_set": put_body})
|
put_body = json.dumps({"quota_set": put_body})
|
||||||
|
@ -39,6 +39,7 @@ class UsedLimitsController(wsgi.Controller):
|
|||||||
'totalShareSnapshotsUsed': 'snapshots',
|
'totalShareSnapshotsUsed': 'snapshots',
|
||||||
'totalShareNetworksUsed': 'share_networks',
|
'totalShareNetworksUsed': 'share_networks',
|
||||||
'totalShareGigabytesUsed': 'gigabytes',
|
'totalShareGigabytesUsed': 'gigabytes',
|
||||||
|
'totalSnapshotGigabytesUsed': 'snapshot_gigabytes',
|
||||||
}
|
}
|
||||||
|
|
||||||
used_limits = {}
|
used_limits = {}
|
||||||
|
@ -44,6 +44,7 @@ class ViewBuilder(object):
|
|||||||
"""
|
"""
|
||||||
limit_names = {
|
limit_names = {
|
||||||
"gigabytes": ["maxTotalShareGigabytes"],
|
"gigabytes": ["maxTotalShareGigabytes"],
|
||||||
|
"snapshot_gigabytes": ["maxTotalSnapshotGigabytes"],
|
||||||
"shares": ["maxTotalShares"],
|
"shares": ["maxTotalShares"],
|
||||||
"snapshots": ["maxTotalShareSnapshots"],
|
"snapshots": ["maxTotalShareSnapshots"],
|
||||||
"share_networks": ["maxTotalShareNetworks"],
|
"share_networks": ["maxTotalShareNetworks"],
|
||||||
|
@ -174,9 +174,7 @@ global_opts = [
|
|||||||
help="Specify list of protocols to be allowed for share "
|
help="Specify list of protocols to be allowed for share "
|
||||||
"creation. Available values are '%s'" % six.text_type(
|
"creation. Available values are '%s'" % six.text_type(
|
||||||
constants.SUPPORTED_SHARE_PROTOCOLS)),
|
constants.SUPPORTED_SHARE_PROTOCOLS)),
|
||||||
cfg.BoolOpt('no_snapshot_gb_quota',
|
]
|
||||||
default=False,
|
|
||||||
help='Whether snapshots count against Gigabyte quota.'), ]
|
|
||||||
|
|
||||||
CONF.register_opts(global_opts)
|
CONF.register_opts(global_opts)
|
||||||
|
|
||||||
|
@ -263,18 +263,15 @@ def _sync_snapshots(context, project_id, user_id, session):
|
|||||||
|
|
||||||
|
|
||||||
def _sync_gigabytes(context, project_id, user_id, session):
|
def _sync_gigabytes(context, project_id, user_id, session):
|
||||||
(_junk, share_gigs) = share_data_get_for_project(context,
|
_junk, share_gigs = share_data_get_for_project(
|
||||||
project_id,
|
context, project_id, user_id, session=session)
|
||||||
user_id,
|
return dict(gigabytes=share_gigs)
|
||||||
session=session)
|
|
||||||
if CONF.no_snapshot_gb_quota:
|
|
||||||
return {'gigabytes': share_gigs}
|
|
||||||
|
|
||||||
(_junk, snap_gigs) = snapshot_data_get_for_project(context,
|
|
||||||
project_id,
|
def _sync_snapshot_gigabytes(context, project_id, user_id, session):
|
||||||
user_id,
|
_junk, snapshot_gigs = snapshot_data_get_for_project(
|
||||||
session=session)
|
context, project_id, user_id, session=session)
|
||||||
return {'gigabytes': share_gigs + snap_gigs}
|
return dict(snapshot_gigabytes=snapshot_gigs)
|
||||||
|
|
||||||
|
|
||||||
def _sync_share_networks(context, project_id, user_id, session):
|
def _sync_share_networks(context, project_id, user_id, session):
|
||||||
@ -289,6 +286,7 @@ QUOTA_SYNC_FUNCTIONS = {
|
|||||||
'_sync_shares': _sync_shares,
|
'_sync_shares': _sync_shares,
|
||||||
'_sync_snapshots': _sync_snapshots,
|
'_sync_snapshots': _sync_snapshots,
|
||||||
'_sync_gigabytes': _sync_gigabytes,
|
'_sync_gigabytes': _sync_gigabytes,
|
||||||
|
'_sync_snapshot_gigabytes': _sync_snapshot_gigabytes,
|
||||||
'_sync_share_networks': _sync_share_networks,
|
'_sync_share_networks': _sync_share_networks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +306,11 @@ class QuotaError(ManilaException):
|
|||||||
|
|
||||||
|
|
||||||
class ShareSizeExceedsAvailableQuota(QuotaError):
|
class ShareSizeExceedsAvailableQuota(QuotaError):
|
||||||
message = _("Requested share or snapshot exceeds "
|
message = _("Requested share exceeds allowed gigabytes quota.")
|
||||||
"allowed gigabytes quota.")
|
|
||||||
|
|
||||||
|
class SnapshotSizeExceedsAvailableQuota(QuotaError):
|
||||||
|
message = _("Requested snapshot exceeds allowed gigabytes quota.")
|
||||||
|
|
||||||
|
|
||||||
class ShareLimitExceeded(QuotaError):
|
class ShareLimitExceeded(QuotaError):
|
||||||
|
@ -39,8 +39,10 @@ quota_opts = [
|
|||||||
help='Number of share snapshots allowed per project.'),
|
help='Number of share snapshots allowed per project.'),
|
||||||
cfg.IntOpt('quota_gigabytes',
|
cfg.IntOpt('quota_gigabytes',
|
||||||
default=1000,
|
default=1000,
|
||||||
help='Number of share gigabytes (snapshots are also included) '
|
help='Number of share gigabytes allowed per project.'),
|
||||||
'allowed per project.'),
|
cfg.IntOpt('quota_snapshot_gigabytes',
|
||||||
|
default=1000,
|
||||||
|
help='Number of snapshot gigabytes allowed per project.'),
|
||||||
cfg.IntOpt('quota_share_networks',
|
cfg.IntOpt('quota_share_networks',
|
||||||
default=10,
|
default=10,
|
||||||
help='Number of share-networks allowed per project.'),
|
help='Number of share-networks allowed per project.'),
|
||||||
@ -1076,6 +1078,8 @@ resources = [
|
|||||||
ReservableResource('shares', '_sync_shares', 'quota_shares'),
|
ReservableResource('shares', '_sync_shares', 'quota_shares'),
|
||||||
ReservableResource('snapshots', '_sync_snapshots', 'quota_snapshots'),
|
ReservableResource('snapshots', '_sync_snapshots', 'quota_snapshots'),
|
||||||
ReservableResource('gigabytes', '_sync_gigabytes', 'quota_gigabytes'),
|
ReservableResource('gigabytes', '_sync_gigabytes', 'quota_gigabytes'),
|
||||||
|
ReservableResource('snapshot_gigabytes', '_sync_snapshot_gigabytes',
|
||||||
|
'quota_snapshot_gigabytes'),
|
||||||
ReservableResource('share_networks', '_sync_share_networks',
|
ReservableResource('share_networks', '_sync_share_networks',
|
||||||
'quota_share_networks'),
|
'quota_share_networks'),
|
||||||
]
|
]
|
||||||
|
@ -272,7 +272,8 @@ class API(base.Base):
|
|||||||
size = share['size']
|
size = share['size']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
reservations = QUOTAS.reserve(context, snapshots=1, gigabytes=size)
|
reservations = QUOTAS.reserve(
|
||||||
|
context, snapshots=1, snapshot_gigabytes=size)
|
||||||
except exception.OverQuota as e:
|
except exception.OverQuota as e:
|
||||||
overs = e.kwargs['overs']
|
overs = e.kwargs['overs']
|
||||||
usages = e.kwargs['usages']
|
usages = e.kwargs['usages']
|
||||||
@ -281,15 +282,15 @@ class API(base.Base):
|
|||||||
def _consumed(name):
|
def _consumed(name):
|
||||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
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 "
|
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||||
"%(s_size)sG snapshot (%(d_consumed)dG of "
|
"%(s_size)sG snapshot (%(d_consumed)dG of "
|
||||||
"%(d_quota)dG already consumed)")
|
"%(d_quota)dG already consumed)")
|
||||||
LOG.warn(msg, {'s_pid': context.project_id,
|
LOG.warn(msg, {'s_pid': context.project_id,
|
||||||
's_size': size,
|
's_size': size,
|
||||||
'd_consumed': _consumed('gigabytes'),
|
'd_consumed': _consumed('gigabytes'),
|
||||||
'd_quota': quotas['gigabytes']})
|
'd_quota': quotas['snapshot_gigabytes']})
|
||||||
raise exception.ShareSizeExceedsAvailableQuota()
|
raise exception.SnapshotSizeExceedsAvailableQuota()
|
||||||
elif 'snapshots' in overs:
|
elif 'snapshots' in overs:
|
||||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||||
"snapshot (%(d_consumed)d snapshots "
|
"snapshot (%(d_consumed)d snapshots "
|
||||||
|
@ -399,10 +399,9 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
else:
|
else:
|
||||||
self.db.share_snapshot_destroy(context, snapshot_id)
|
self.db.share_snapshot_destroy(context, snapshot_id)
|
||||||
try:
|
try:
|
||||||
reservations = QUOTAS.reserve(context,
|
reservations = QUOTAS.reserve(
|
||||||
project_id=project_id,
|
context, project_id=project_id, snapshots=-1,
|
||||||
snapshots=-1,
|
snapshot_gigabytes=-snapshot_ref['size'])
|
||||||
gigabytes=-snapshot_ref['size'])
|
|
||||||
except Exception:
|
except Exception:
|
||||||
reservations = None
|
reservations = None
|
||||||
LOG.exception(_LE("Failed to update usages deleting snapshot"))
|
LOG.exception(_LE("Failed to update usages deleting snapshot"))
|
||||||
|
@ -498,7 +498,7 @@ class ShareAPITestCase(test.TestCase):
|
|||||||
share_api.policy.check_policy.assert_called_once_with(
|
share_api.policy.check_policy.assert_called_once_with(
|
||||||
self.context, 'share', 'create_snapshot', share)
|
self.context, 'share', 'create_snapshot', share)
|
||||||
quota.QUOTAS.reserve.assert_called_once_with(
|
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(
|
quota.QUOTAS.commit.assert_called_once_with(
|
||||||
self.context, 'reservation')
|
self.context, 'reservation')
|
||||||
db_driver.share_snapshot_create.assert_called_once_with(
|
db_driver.share_snapshot_create.assert_called_once_with(
|
||||||
|
@ -616,20 +616,17 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected_all_context = {
|
expected_all_context = {
|
||||||
"shares": {"limit": 10, "in_use": 2, "reserved": 0, },
|
"shares": {"limit": 10, "in_use": 2, "reserved": 0, },
|
||||||
"gigabytes": {"limit": 50, "in_use": 10, "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, },
|
"share_networks": {"limit": 10, "in_use": 0, "reserved": 0, },
|
||||||
}
|
}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(DbQuotaDriverTestCase, self).setUp()
|
super(DbQuotaDriverTestCase, self).setUp()
|
||||||
|
self.flags(
|
||||||
self.flags(quota_shares=10,
|
quota_shares=10, quota_snapshots=10, quota_gigabytes=1000,
|
||||||
quota_snapshots=10,
|
quota_snapshot_gigabytes=1000, reservation_expire=86400,
|
||||||
quota_gigabytes=1000,
|
until_refresh=0, max_age=0)
|
||||||
reservation_expire=86400,
|
|
||||||
until_refresh=0,
|
|
||||||
max_age=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.driver = quota.DbQuotaDriver()
|
self.driver = quota.DbQuotaDriver()
|
||||||
|
|
||||||
@ -649,17 +646,18 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": 10,
|
"shares": 10,
|
||||||
"gigabytes": 1000,
|
"gigabytes": 1000,
|
||||||
|
"snapshot_gigabytes": 1000,
|
||||||
"snapshots": 10,
|
"snapshots": 10,
|
||||||
"share_networks": 10,
|
"share_networks": 10,
|
||||||
}
|
}
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
def _stub_quota_class_get_all_by_name(self):
|
def _stub_quota_class_get_all_by_name(self):
|
||||||
# Stub out quota_class_get_all_by_name
|
# Stub out quota_class_get_all_by_name
|
||||||
def fake_qcgabn(context, quota_class):
|
def fake_qcgabn(context, quota_class):
|
||||||
self.calls.append('quota_class_get_all_by_name')
|
self.calls.append('quota_class_get_all_by_name')
|
||||||
self.assertEqual(quota_class, 'test_class')
|
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)
|
self.mock_object(db, 'quota_class_get_all_by_name', fake_qcgabn)
|
||||||
|
|
||||||
def test_get_class_quotas(self):
|
def test_get_class_quotas(self):
|
||||||
@ -671,10 +669,11 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": 10,
|
"shares": 10,
|
||||||
"gigabytes": 500,
|
"gigabytes": 500,
|
||||||
|
"snapshot_gigabytes": 50,
|
||||||
"snapshots": 10,
|
"snapshots": 10,
|
||||||
"share_networks": 10,
|
"share_networks": 10,
|
||||||
}
|
}
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
def test_get_class_quotas_no_defaults(self):
|
def test_get_class_quotas_no_defaults(self):
|
||||||
self._stub_quota_class_get_all_by_name()
|
self._stub_quota_class_get_all_by_name()
|
||||||
@ -682,27 +681,35 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
'test_class', False)
|
'test_class', False)
|
||||||
|
|
||||||
self.assertEqual(self.calls, ['quota_class_get_all_by_name'])
|
self.assertEqual(self.calls, ['quota_class_get_all_by_name'])
|
||||||
self.assertEqual(result, dict(shares=10,
|
self.assertEqual(
|
||||||
gigabytes=500))
|
dict(shares=10, gigabytes=500, snapshot_gigabytes=50), result)
|
||||||
|
|
||||||
def _stub_get_by_project_and_user(self):
|
def _stub_get_by_project_and_user(self):
|
||||||
def fake_qgabpu(context, project_id, user_id):
|
def fake_qgabpu(context, project_id, user_id):
|
||||||
self.calls.append('quota_get_all_by_project_and_user')
|
self.calls.append('quota_get_all_by_project_and_user')
|
||||||
self.assertEqual(project_id, 'test_project')
|
self.assertEqual(project_id, 'test_project')
|
||||||
self.assertEqual(user_id, 'fake_user')
|
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):
|
def fake_qgabp(context, project_id):
|
||||||
self.calls.append('quota_get_all_by_project')
|
self.calls.append('quota_get_all_by_project')
|
||||||
self.assertEqual(project_id, 'test_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):
|
def fake_qugabpu(context, project_id, user_id):
|
||||||
self.calls.append('quota_usage_get_all_by_project_and_user')
|
self.calls.append('quota_usage_get_all_by_project_and_user')
|
||||||
self.assertEqual(project_id, 'test_project')
|
self.assertEqual(project_id, 'test_project')
|
||||||
self.assertEqual(user_id, 'fake_user')
|
self.assertEqual(user_id, 'fake_user')
|
||||||
return dict(shares=dict(in_use=2, reserved=0),
|
return dict(
|
||||||
gigabytes=dict(in_use=10, reserved=0), )
|
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_and_user', fake_qgabpu)
|
||||||
self.mock_object(db, 'quota_get_all_by_project', fake_qgabp)
|
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_usage_get_all_by_project_and_user',
|
||||||
'quota_class_get_all_by_name',
|
'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 _stub_get_by_project(self):
|
||||||
def fake_qgabp(context, project_id):
|
def fake_qgabp(context, project_id):
|
||||||
self.calls.append('quota_get_all_by_project')
|
self.calls.append('quota_get_all_by_project')
|
||||||
self.assertEqual(project_id, 'test_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):
|
def fake_qugabp(context, project_id):
|
||||||
self.calls.append('quota_usage_get_all_by_project')
|
self.calls.append('quota_usage_get_all_by_project')
|
||||||
self.assertEqual(project_id, 'test_project')
|
self.assertEqual(project_id, 'test_project')
|
||||||
return dict(shares=dict(in_use=2, reserved=0),
|
return dict(
|
||||||
gigabytes=dict(in_use=10, reserved=0), )
|
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_get_all_by_project', fake_qgabp)
|
||||||
self.mock_object(db, 'quota_usage_get_all_by_project', fake_qugabp)
|
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',
|
self.assertEqual(self.calls, ['quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project',
|
'quota_usage_get_all_by_project',
|
||||||
'quota_class_get_all_by_name', ])
|
'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):
|
def test_get_project_quotas_with_remains(self):
|
||||||
self._stub_get_by_project()
|
self._stub_get_by_project()
|
||||||
@ -772,7 +783,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
'quota_get_all_by_project',
|
'quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project_and_user',
|
'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):
|
def test_get_project_quotas_alt_context_no_class(self):
|
||||||
self._stub_get_by_project()
|
self._stub_get_by_project()
|
||||||
@ -782,7 +793,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(self.calls, ['quota_get_all_by_project',
|
self.assertEqual(self.calls, ['quota_get_all_by_project',
|
||||||
'quota_usage_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):
|
def test_get_user_quotas_alt_context_with_class(self):
|
||||||
self._stub_get_by_project_and_user()
|
self._stub_get_by_project_and_user()
|
||||||
@ -797,7 +808,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
'quota_usage_get_all_by_project_and_user',
|
'quota_usage_get_all_by_project_and_user',
|
||||||
'quota_class_get_all_by_name',
|
'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):
|
def test_get_project_quotas_alt_context_with_class(self):
|
||||||
self._stub_get_by_project()
|
self._stub_get_by_project()
|
||||||
@ -808,7 +819,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
self.assertEqual(self.calls, ['quota_get_all_by_project',
|
self.assertEqual(self.calls, ['quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project',
|
'quota_usage_get_all_by_project',
|
||||||
'quota_class_get_all_by_name', ])
|
'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):
|
def test_get_user_quotas_no_defaults(self):
|
||||||
self._stub_get_by_project_and_user()
|
self._stub_get_by_project_and_user()
|
||||||
@ -826,8 +837,10 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": {"limit": 10, "in_use": 2, "reserved": 0, },
|
"shares": {"limit": 10, "in_use": 2, "reserved": 0, },
|
||||||
"gigabytes": {"limit": 50, "in_use": 10, "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):
|
def test_get_project_quotas_no_defaults(self):
|
||||||
self._stub_get_by_project()
|
self._stub_get_by_project()
|
||||||
@ -841,8 +854,9 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": {"limit": 10, "in_use": 2, "reserved": 0, },
|
"shares": {"limit": 10, "in_use": 2, "reserved": 0, },
|
||||||
"gigabytes": {"limit": 50, "in_use": 10, "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):
|
def test_get_user_quotas_no_usages(self):
|
||||||
self._stub_get_by_project_and_user()
|
self._stub_get_by_project_and_user()
|
||||||
@ -858,10 +872,11 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": {"limit": 10, },
|
"shares": {"limit": 10, },
|
||||||
"gigabytes": {"limit": 50, },
|
"gigabytes": {"limit": 50, },
|
||||||
|
"snapshot_gigabytes": {"limit": 50, },
|
||||||
"snapshots": {"limit": 10, },
|
"snapshots": {"limit": 10, },
|
||||||
"share_networks": {"limit": 10, },
|
"share_networks": {"limit": 10, },
|
||||||
}
|
}
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected, result)
|
||||||
|
|
||||||
def test_get_project_quotas_no_usages(self):
|
def test_get_project_quotas_no_usages(self):
|
||||||
self._stub_get_by_project()
|
self._stub_get_by_project()
|
||||||
@ -874,10 +889,11 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": {"limit": 10, },
|
"shares": {"limit": 10, },
|
||||||
"gigabytes": {"limit": 50, },
|
"gigabytes": {"limit": 50, },
|
||||||
|
"snapshot_gigabytes": {"limit": 50, },
|
||||||
"snapshots": {"limit": 10, },
|
"snapshots": {"limit": 10, },
|
||||||
"share_networks": {"limit": 10, },
|
"share_networks": {"limit": 10, },
|
||||||
}
|
}
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
def _stub_get_settable_quotas(self):
|
def _stub_get_settable_quotas(self):
|
||||||
def fake_get_project_quotas(context, resources, project_id,
|
def fake_get_project_quotas(context, resources, project_id,
|
||||||
@ -928,6 +944,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": {"minimum": 0, "maximum": 12, },
|
"shares": {"minimum": 0, "maximum": 12, },
|
||||||
"gigabytes": {"minimum": 0, "maximum": 1000, },
|
"gigabytes": {"minimum": 0, "maximum": 1000, },
|
||||||
|
"snapshot_gigabytes": {"minimum": 0, "maximum": 1000, },
|
||||||
"snapshots": {"minimum": 0, "maximum": 10, },
|
"snapshots": {"minimum": 0, "maximum": 10, },
|
||||||
"share_networks": {"minimum": 0, "maximum": 10, },
|
"share_networks": {"minimum": 0, "maximum": 10, },
|
||||||
}
|
}
|
||||||
@ -945,6 +962,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||||||
expected = {
|
expected = {
|
||||||
"shares": {"minimum": 0, "maximum": -1, },
|
"shares": {"minimum": 0, "maximum": -1, },
|
||||||
"gigabytes": {"minimum": 0, "maximum": -1, },
|
"gigabytes": {"minimum": 0, "maximum": -1, },
|
||||||
|
"snapshot_gigabytes": {"minimum": 0, "maximum": -1, },
|
||||||
"snapshots": {"minimum": 0, "maximum": -1, },
|
"snapshots": {"minimum": 0, "maximum": -1, },
|
||||||
"share_networks": {"minimum": 0, "maximum": -1, },
|
"share_networks": {"minimum": 0, "maximum": -1, },
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user