Add API to retrieve default quotas
Currently there is no support to retrieve default quotas set for all projects. This patch adds a new API function to get default quotas. GET /v2.0/quotas/<tenant-id>/default DocImpact: Document new API to used to retrieve default quotas APIImpact: New Read-only API to retrieve default quotas Change-Id: If40a44348e305da444acd6196d2e0c04202b8f7a Closes-Bug: #1204956
This commit is contained in:
parent
ad668e1941
commit
f5a2ee300d
|
@ -33,6 +33,22 @@ class DbQuotaDriver(object):
|
||||||
The default driver utilizes the local database.
|
The default driver utilizes the local database.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_default_quotas(context, resources, tenant_id):
|
||||||
|
"""Given a list of resources, retrieve the default quotas set for
|
||||||
|
a tenant.
|
||||||
|
|
||||||
|
:param context: The request context, for access checks.
|
||||||
|
:param resources: A dictionary of the registered resource keys.
|
||||||
|
:param tenant_id: The ID of the tenant to return default quotas for.
|
||||||
|
:return dict: from resource name to dict of name and limit
|
||||||
|
"""
|
||||||
|
# Currently the tenant_id parameter is unused, since all tenants
|
||||||
|
# share the same default values. This may change in the future so
|
||||||
|
# we include tenant-id to remain backwards compatible.
|
||||||
|
return dict((key, resource.default)
|
||||||
|
for key, resource in resources.items())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_tenant_quotas(context, resources, tenant_id):
|
def get_tenant_quotas(context, resources, tenant_id):
|
||||||
"""Given a list of resources, retrieve the quotas for the given
|
"""Given a list of resources, retrieve the quotas for the given
|
||||||
|
|
|
@ -31,6 +31,8 @@ from neutron import quota
|
||||||
from neutron.quota import resource_registry
|
from neutron.quota import resource_registry
|
||||||
from neutron import wsgi
|
from neutron import wsgi
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_QUOTAS_ACTION = 'default'
|
||||||
RESOURCE_NAME = 'quota'
|
RESOURCE_NAME = 'quota'
|
||||||
RESOURCE_COLLECTION = RESOURCE_NAME + "s"
|
RESOURCE_COLLECTION = RESOURCE_NAME + "s"
|
||||||
QUOTAS = quota.QUOTAS
|
QUOTAS = quota.QUOTAS
|
||||||
|
@ -67,6 +69,16 @@ class QuotaSetsController(wsgi.Controller):
|
||||||
resource_registry.get_all_resources(),
|
resource_registry.get_all_resources(),
|
||||||
tenant_id)
|
tenant_id)
|
||||||
|
|
||||||
|
def default(self, request, id):
|
||||||
|
if id != request.context.tenant_id:
|
||||||
|
self._check_admin(request.context,
|
||||||
|
reason=_("Only admin is authorized "
|
||||||
|
"to access quotas for another tenant"))
|
||||||
|
return {self._resource_name: self._driver.get_default_quotas(
|
||||||
|
context=request.context,
|
||||||
|
resources=resource_registry.get_all_resources(),
|
||||||
|
tenant_id=id)}
|
||||||
|
|
||||||
def create(self, request, body=None):
|
def create(self, request, body=None):
|
||||||
msg = _('POST requests are not supported on this resource.')
|
msg = _('POST requests are not supported on this resource.')
|
||||||
raise webob.exc.HTTPNotImplemented(msg)
|
raise webob.exc.HTTPNotImplemented(msg)
|
||||||
|
@ -144,6 +156,7 @@ class Quotasv2(extensions.ExtensionDescriptor):
|
||||||
return [extensions.ResourceExtension(
|
return [extensions.ResourceExtension(
|
||||||
Quotasv2.get_alias(),
|
Quotasv2.get_alias(),
|
||||||
controller,
|
controller,
|
||||||
|
member_actions={DEFAULT_QUOTAS_ACTION: 'GET'},
|
||||||
collection_actions={'tenant': 'GET'})]
|
collection_actions={'tenant': 'GET'})]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -76,6 +76,13 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase):
|
||||||
quotas = self.plugin.get_tenant_quotas(self.context, defaults, PROJECT)
|
quotas = self.plugin.get_tenant_quotas(self.context, defaults, PROJECT)
|
||||||
self.assertEqual(4, quotas[RESOURCE])
|
self.assertEqual(4, quotas[RESOURCE])
|
||||||
|
|
||||||
|
def test_get_default_quotas(self):
|
||||||
|
defaults = {RESOURCE: TestResource(RESOURCE, 4)}
|
||||||
|
user_ctx = context.Context(user_id=PROJECT, tenant_id=PROJECT)
|
||||||
|
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
|
||||||
|
quotas = self.plugin.get_default_quotas(user_ctx, defaults, PROJECT)
|
||||||
|
self.assertEqual(4, quotas[RESOURCE])
|
||||||
|
|
||||||
def test_get_tenant_quotas(self):
|
def test_get_tenant_quotas(self):
|
||||||
user_ctx = context.Context(user_id=PROJECT, tenant_id=PROJECT)
|
user_ctx = context.Context(user_id=PROJECT, tenant_id=PROJECT)
|
||||||
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
|
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
|
||||||
|
|
|
@ -35,6 +35,7 @@ from neutron.tests import tools
|
||||||
from neutron.tests.unit.api.v2 import test_base
|
from neutron.tests.unit.api.v2 import test_base
|
||||||
from neutron.tests.unit import testlib_api
|
from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
|
DEFAULT_QUOTAS_ACTION = 'default'
|
||||||
TARGET_PLUGIN = 'neutron.plugins.ml2.plugin.Ml2Plugin'
|
TARGET_PLUGIN = 'neutron.plugins.ml2.plugin.Ml2Plugin'
|
||||||
|
|
||||||
_get_path = test_base._get_path
|
_get_path = test_base._get_path
|
||||||
|
@ -126,6 +127,44 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
|
||||||
'port': -1,
|
'port': -1,
|
||||||
'extra1': -1})
|
'extra1': -1})
|
||||||
|
|
||||||
|
def test_show_default_quotas_with_admin(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'neutron.context': context.Context('', tenant_id + '2',
|
||||||
|
is_admin=True)}
|
||||||
|
res = self.api.get(_get_path('quotas', id=tenant_id,
|
||||||
|
action=DEFAULT_QUOTAS_ACTION,
|
||||||
|
fmt=self.fmt),
|
||||||
|
extra_environ=env)
|
||||||
|
self.assertEqual(200, res.status_int)
|
||||||
|
quota = self.deserialize(res)
|
||||||
|
self.assertEqual(10, quota['quota']['network'])
|
||||||
|
self.assertEqual(10, quota['quota']['subnet'])
|
||||||
|
self.assertEqual(50, quota['quota']['port'])
|
||||||
|
|
||||||
|
def test_show_default_quotas_with_owner_tenant(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'neutron.context': context.Context('', tenant_id,
|
||||||
|
is_admin=False)}
|
||||||
|
res = self.api.get(_get_path('quotas', id=tenant_id,
|
||||||
|
action=DEFAULT_QUOTAS_ACTION,
|
||||||
|
fmt=self.fmt),
|
||||||
|
extra_environ=env)
|
||||||
|
self.assertEqual(200, res.status_int)
|
||||||
|
quota = self.deserialize(res)
|
||||||
|
self.assertEqual(10, quota['quota']['network'])
|
||||||
|
self.assertEqual(10, quota['quota']['subnet'])
|
||||||
|
self.assertEqual(50, quota['quota']['port'])
|
||||||
|
|
||||||
|
def test_show_default_quotas_without_admin_forbidden_returns_403(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'neutron.context': context.Context('', tenant_id + '2',
|
||||||
|
is_admin=False)}
|
||||||
|
res = self.api.get(_get_path('quotas', id=tenant_id,
|
||||||
|
action=DEFAULT_QUOTAS_ACTION,
|
||||||
|
fmt=self.fmt),
|
||||||
|
extra_environ=env, expect_errors=True)
|
||||||
|
self.assertEqual(403, res.status_int)
|
||||||
|
|
||||||
def test_show_quotas_with_admin(self):
|
def test_show_quotas_with_admin(self):
|
||||||
tenant_id = 'tenant_id1'
|
tenant_id = 'tenant_id1'
|
||||||
env = {'neutron.context': context.Context('', tenant_id + '2',
|
env = {'neutron.context': context.Context('', tenant_id + '2',
|
||||||
|
|
Loading…
Reference in New Issue