import webob
from quantum.api import extensions
+from quantum.api.v2.attributes import convert_to_int
from quantum.api.v2 import base
-from quantum.common import exceptions
+from quantum.api.v2 import resource
+from quantum.common import exceptions as q_exc
from quantum.manager import QuantumManager
from quantum.openstack.common import importutils
from quantum import quota
attr_dict = EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION]
attr_dict[quota_resource] = {'allow_post': False,
'allow_put': True,
- 'convert_to': int,
+ 'convert_to': convert_to_int,
'is_visible': True}
self._update_extended_attributes = False
- def _get_body(self, request):
- body = self._deserialize(request.body,
- request.best_match_content_type())
- if self._update_extended_attributes:
- self._update_attributes()
-
- attr_info = EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION]
- req_body = base.Controller.prepare_request_body(
- request.context, body, False, self._resource_name, attr_info)
- return req_body
-
def _get_quotas(self, request, tenant_id):
return self._driver.get_tenant_quotas(
request.context, QUOTAS.resources, tenant_id)
def index(self, request):
context = request.context
- if not context.is_admin:
- raise webob.exc.HTTPForbidden()
+ self._check_admin(context)
return {self._resource_name + "s":
self._driver.get_all_quotas(context, QUOTAS.resources)}
"""Retrieve the tenant info in context."""
context = request.context
if not context.tenant_id:
- raise webob.exc.HTTPBadRequest('invalid tenant')
+ raise q_exc.QuotaMissingTenant()
return {'tenant': {'tenant_id': context.tenant_id}}
def show(self, request, id):
- context = request.context
- tenant_id = id
- if not tenant_id:
- raise webob.exc.HTTPBadRequest('invalid tenant')
- if (tenant_id != context.tenant_id and
- not context.is_admin):
- raise webob.exc.HTTPForbidden()
- return {self._resource_name:
- self._get_quotas(request, tenant_id)}
-
- def _check_modification_delete_privilege(self, context, tenant_id):
- if not tenant_id:
- raise webob.exc.HTTPBadRequest('invalid tenant')
+ if id != request.context.tenant_id:
+ self._check_admin(request.context,
+ reason=_("Non-admin is not authorised "
+ "to access quotas for another tenant"))
+ return {self._resource_name: self._get_quotas(request, id)}
+
+ def _check_admin(self, context,
+ reason=_("Only admin can view or configure quota")):
if not context.is_admin:
- raise webob.exc.HTTPForbidden()
- return tenant_id
+ raise q_exc.AdminRequired(reason=reason)
def delete(self, request, id):
- tenant_id = self._check_modification_delete_privilege(request.context,
- id)
- self._driver.delete_tenant_quota(request.context, tenant_id)
-
- def update(self, request, id):
- tenant_id = self._check_modification_delete_privilege(request.context,
- id)
- req_body = self._get_body(request)
- for key in req_body[self._resource_name].keys():
- if key in QUOTAS.resources:
- value = int(req_body[self._resource_name][key])
- self._driver.update_quota_limit(request.context,
- tenant_id,
- key,
- value)
- return {self._resource_name: self._get_quotas(request, tenant_id)}
+ self._check_admin(request.context)
+ self._driver.delete_tenant_quota(request.context, id)
+
+ def update(self, request, id, body=None):
+ self._check_admin(request.context)
+ if self._update_extended_attributes:
+ self._update_attributes()
+ body = base.Controller.prepare_request_body(
+ request.context, body, False, self._resource_name,
+ EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION])
+ for key, value in body[self._resource_name].iteritems():
+ self._driver.update_quota_limit(request.context, id, key, value)
+ return {self._resource_name: self._get_quotas(request, id)}
class Quotasv2(extensions.ExtensionDescriptor):
@classmethod
def get_resources(cls):
""" Returns Ext Resources """
- controller = QuotaSetsController(QuantumManager.get_plugin())
+ controller = resource.Resource(
+ QuotaSetsController(QuantumManager.get_plugin()),
+ faults=base.FAULT_MAP)
return [extensions.ResourceExtension(
Quotasv2.get_alias(),
controller,
from quantum import manager
from quantum.plugins.linuxbridge.db import l2network_db_v2
from quantum import quota
-from quantum.tests import base
from quantum.tests.unit import test_api_v2
from quantum.tests.unit import test_extensions
from quantum.tests.unit import testlib_api
class QuotaExtensionTestCase(testlib_api.WebTestCase):
- fmt = 'json'
def setUp(self):
super(QuotaExtensionTestCase, self).setUp()
# Update the plugin and extensions path
cfg.CONF.set_override('core_plugin', TARGET_PLUGIN)
- cfg.CONF.set_override(
- 'quota_driver',
- 'quantum.db.quota_db.DbQuotaDriver',
- group='QUOTAS')
cfg.CONF.set_override(
'quota_items',
['network', 'subnet', 'port', 'extra1'],
app = config.load_paste_app('extensions_test_app')
ext_middleware = extensions.ExtensionMiddleware(app, ext_mgr=ext_mgr)
self.api = webtest.TestApp(ext_middleware)
- super(QuotaExtensionTestCase, self).setUp()
def tearDown(self):
self._plugin_patcher.stop()
attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
super(QuotaExtensionTestCase, self).tearDown()
+
+class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
+ fmt = 'json'
+
+ def setUp(self):
+ cfg.CONF.set_override(
+ 'quota_driver',
+ 'quantum.db.quota_db.DbQuotaDriver',
+ group='QUOTAS')
+ super(QuotaExtensionDbTestCase, self).setUp()
+
def test_quotas_loaded_right(self):
res = self.api.get(_get_path('quotas', fmt=self.fmt))
quota = self.deserialize(res)
res = self.api.get(_get_path('quotas', id=tenant_id, 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_quotas_without_admin_forbidden(self):
+ def test_show_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1'
env = {'quantum.context': context.Context('', tenant_id + '2',
is_admin=False)}
extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int)
- def test_update_quotas_without_admin_forbidden(self):
+ def test_show_quotas_with_owner_tenant(self):
+ tenant_id = 'tenant_id1'
+ env = {'quantum.context': context.Context('', tenant_id,
+ is_admin=False)}
+ res = self.api.get(_get_path('quotas', id=tenant_id, 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_list_quotas_with_admin(self):
+ tenant_id = 'tenant_id1'
+ env = {'quantum.context': context.Context('', tenant_id,
+ is_admin=True)}
+ res = self.api.get(_get_path('quotas', fmt=self.fmt),
+ extra_environ=env)
+ self.assertEqual(200, res.status_int)
+ quota = self.deserialize(res)
+ self.assertEqual([], quota['quotas'])
+
+ def test_list_quotas_without_admin_forbidden_returns_403(self):
+ tenant_id = 'tenant_id1'
+ env = {'quantum.context': context.Context('', tenant_id,
+ is_admin=False)}
+ res = self.api.get(_get_path('quotas', fmt=self.fmt),
+ extra_environ=env, expect_errors=True)
+ self.assertEqual(403, res.status_int)
+
+ def test_update_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1'
env = {'quantum.context': context.Context('', tenant_id,
is_admin=False)}
expect_errors=True)
self.assertEqual(403, res.status_int)
+ def test_update_quotas_with_non_integer_returns_400(self):
+ tenant_id = 'tenant_id1'
+ env = {'quantum.context': context.Context('', tenant_id,
+ is_admin=True)}
+ quotas = {'quota': {'network': 'abc'}}
+ res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
+ self.serialize(quotas), extra_environ=env,
+ expect_errors=True)
+ self.assertEqual(400, res.status_int)
+
+ def test_update_quotas_with_non_support_resource_returns_400(self):
+ tenant_id = 'tenant_id1'
+ env = {'quantum.context': context.Context('', tenant_id,
+ is_admin=True)}
+ quotas = {'quota': {'abc': 100}}
+ res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
+ self.serialize(quotas), extra_environ=env,
+ expect_errors=True)
+ self.assertEqual(400, res.status_int)
+
def test_update_quotas_with_admin(self):
tenant_id = 'tenant_id1'
env = {'quantum.context': context.Context('', tenant_id + '2',
extra_environ=env2)
quota = self.deserialize(res)
self.assertEqual(100, quota['quota']['network'])
+ self.assertEqual(10, quota['quota']['subnet'])
+ self.assertEqual(50, quota['quota']['port'])
def test_update_attributes(self):
tenant_id = 'tenant_id1'
extra_environ=env)
self.assertEqual(204, res.status_int)
- def test_delete_quotas_without_admin_forbidden(self):
+ def test_delete_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1'
env = {'quantum.context': context.Context('', tenant_id,
is_admin=False)}
extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int)
- def test_quotas_loaded_bad(self):
+ def test_quotas_loaded_bad_returns_404(self):
try:
res = self.api.get(_get_path('quotas'), expect_errors=True)
self.assertEqual(404, res.status_int)
tenant_id,
network=-1)
+ def test_quotas_get_tenant_from_request_context(self):
+ tenant_id = 'tenant_id1'
+ env = {'quantum.context': context.Context('', tenant_id,
+ is_admin=True)}
+ res = self.api.get(_get_path('quotas/tenant', fmt=self.fmt),
+ extra_environ=env)
+ self.assertEqual(200, res.status_int)
+ quota = self.deserialize(res)
+ self.assertEqual(quota['tenant']['tenant_id'], tenant_id)
-class QuotaExtensionTestCaseXML(QuotaExtensionTestCase):
- fmt = 'xml'
-
-
-class QuotaExtensionCfgTestCase(testlib_api.WebTestCase):
- fmt = 'json'
-
- def setUp(self):
- super(QuotaExtensionCfgTestCase, self).setUp()
- db._ENGINE = None
- db._MAKER = None
- # Ensure 'stale' patched copies of the plugin are never returned
- manager.QuantumManager._instance = None
-
- # Ensure existing ExtensionManager is not used
- extensions.PluginAwareExtensionManager._instance = None
-
- # Save the global RESOURCE_ATTRIBUTE_MAP
- self.saved_attr_map = {}
- for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
- self.saved_attr_map[resource] = attrs.copy()
+ def test_quotas_get_tenant_from_empty_request_context_returns_400(self):
+ env = {'quantum.context': context.Context('', '',
+ is_admin=True)}
+ res = self.api.get(_get_path('quotas/tenant', fmt=self.fmt),
+ extra_environ=env, expect_errors=True)
+ self.assertEqual(400, res.status_int)
- # Create the default configurations
- args = ['--config-file', test_extensions.etcdir('quantum.conf.test')]
- config.parse(args=args)
- # Update the plugin and extensions path
- cfg.CONF.set_override('core_plugin', TARGET_PLUGIN)
- cfg.CONF.set_override(
- 'quota_items',
- ['network', 'subnet', 'port', 'extra1'],
- group='QUOTAS')
- quota.QUOTAS = quota.QuotaEngine()
- quota.register_resources_from_config()
- self._plugin_patcher = mock.patch(TARGET_PLUGIN, autospec=True)
- self.plugin = self._plugin_patcher.start()
- self.plugin.return_value.supported_extension_aliases = ['quotas']
- # QUOTAS will regester the items in conf when starting
- # extra1 here is added later, so have to do it manually
- quota.QUOTAS.register_resource_by_name('extra1')
- ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
- l2network_db_v2.initialize()
- app = config.load_paste_app('extensions_test_app')
- ext_middleware = extensions.ExtensionMiddleware(app, ext_mgr=ext_mgr)
- self.api = webtest.TestApp(ext_middleware)
- super(QuotaExtensionCfgTestCase, self).setUp()
+class QuotaExtensionDbTestCaseXML(QuotaExtensionDbTestCase):
+ fmt = 'xml'
- def tearDown(self):
- self._plugin_patcher.stop()
- self.api = None
- self.plugin = None
- db._ENGINE = None
- db._MAKER = None
- cfg.CONF.reset()
- # Restore the global RESOURCE_ATTRIBUTE_MAP
- attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
- super(QuotaExtensionCfgTestCase, self).tearDown()
+class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
+ fmt = 'json'
def test_quotas_default_values(self):
tenant_id = 'tenant_id1'