Show default configuration Quotas
Fixes bug 1144076 The patch set shows the defualt quotas that exist in the configuration file. This is if the DB_QUOTA_DRIVER is not configured. In this case the user is required to update the configuration file and restart the service. Change-Id: I5517c0215e8cfa71453ee38c34d8249e74346fdf
This commit is contained in:
parent
72cb17b55f
commit
b62324360b
@ -41,7 +41,7 @@ class QuotaSetsController(wsgi.Controller):
|
|||||||
def __init__(self, plugin):
|
def __init__(self, plugin):
|
||||||
self._resource_name = RESOURCE_NAME
|
self._resource_name = RESOURCE_NAME
|
||||||
self._plugin = plugin
|
self._plugin = plugin
|
||||||
self._driver = importutils.import_class(DB_QUOTA_DRIVER)
|
self._driver = importutils.import_class(cfg.CONF.QUOTAS.quota_driver)
|
||||||
self._update_extended_attributes = True
|
self._update_extended_attributes = True
|
||||||
|
|
||||||
def _update_attributes(self):
|
def _update_attributes(self):
|
||||||
@ -56,7 +56,7 @@ class QuotaSetsController(wsgi.Controller):
|
|||||||
def _get_body(self, request):
|
def _get_body(self, request):
|
||||||
body = self._deserialize(request.body,
|
body = self._deserialize(request.body,
|
||||||
request.best_match_content_type())
|
request.best_match_content_type())
|
||||||
if self._update_extended_attributes is True:
|
if self._update_extended_attributes:
|
||||||
self._update_attributes()
|
self._update_attributes()
|
||||||
|
|
||||||
attr_info = EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION]
|
attr_info = EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION]
|
||||||
@ -69,7 +69,7 @@ class QuotaSetsController(wsgi.Controller):
|
|||||||
request.context, QUOTAS.resources, tenant_id)
|
request.context, QUOTAS.resources, tenant_id)
|
||||||
|
|
||||||
def create(self, request, body=None):
|
def create(self, request, body=None):
|
||||||
raise NotImplementedError()
|
raise webob.exc.HTTPNotImplemented()
|
||||||
|
|
||||||
def index(self, request):
|
def index(self, request):
|
||||||
context = request.context
|
context = request.context
|
||||||
@ -127,7 +127,7 @@ class Quotasv2(extensions.ExtensionDescriptor):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls):
|
def get_name(cls):
|
||||||
return "Quotas for each tenant"
|
return "Quota management support"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_alias(cls):
|
def get_alias(cls):
|
||||||
@ -135,8 +135,10 @@ class Quotasv2(extensions.ExtensionDescriptor):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_description(cls):
|
def get_description(cls):
|
||||||
return ("Expose functions for cloud admin to update quotas"
|
description = 'Expose functions for quotas management'
|
||||||
"for each tenant")
|
if cfg.CONF.QUOTAS.quota_driver == DB_QUOTA_DRIVER:
|
||||||
|
description += ' per tenant'
|
||||||
|
return description
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_namespace(cls):
|
def get_namespace(cls):
|
||||||
@ -160,8 +162,3 @@ class Quotasv2(extensions.ExtensionDescriptor):
|
|||||||
return EXTENDED_ATTRIBUTES_2_0
|
return EXTENDED_ATTRIBUTES_2_0
|
||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def check_env(self):
|
|
||||||
if cfg.CONF.QUOTAS.quota_driver != DB_QUOTA_DRIVER:
|
|
||||||
msg = _('Quota driver %s is needed.') % DB_QUOTA_DRIVER
|
|
||||||
raise exceptions.InvalidExtenstionEnv(reason=msg)
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"""Quotas for instances, volumes, and floating ips."""
|
"""Quotas for instances, volumes, and floating ips."""
|
||||||
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
import webob
|
||||||
|
|
||||||
from quantum.common import exceptions
|
from quantum.common import exceptions
|
||||||
from quantum.openstack.common import importutils
|
from quantum.openstack.common import importutils
|
||||||
@ -124,6 +125,26 @@ class ConfDriver(object):
|
|||||||
raise exceptions.OverQuota(overs=sorted(overs), quotas=quotas,
|
raise exceptions.OverQuota(overs=sorted(overs), quotas=quotas,
|
||||||
usages={})
|
usages={})
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_tenant_quotas(context, resources, tenant_id):
|
||||||
|
quotas = {}
|
||||||
|
sub_resources = dict((k, v) for k, v in resources.items())
|
||||||
|
for resource in sub_resources.values():
|
||||||
|
quotas[resource.name] = resource.default
|
||||||
|
return quotas
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_quotas(context, resources):
|
||||||
|
return []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_tenant_quota(context, tenant_id):
|
||||||
|
raise webob.exc.HTTPForbidden()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_quota_limit(context, tenant_id, resource, limit):
|
||||||
|
raise webob.exc.HTTPForbidden()
|
||||||
|
|
||||||
|
|
||||||
class BaseResource(object):
|
class BaseResource(object):
|
||||||
"""Describe a single resource for quota checking."""
|
"""Describe a single resource for quota checking."""
|
||||||
|
@ -213,3 +213,106 @@ class QuotaExtensionTestCase(testlib_api.WebTestCase):
|
|||||||
|
|
||||||
class QuotaExtensionTestCaseXML(QuotaExtensionTestCase):
|
class QuotaExtensionTestCaseXML(QuotaExtensionTestCase):
|
||||||
fmt = 'xml'
|
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()
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
def test_quotas_default_values(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'quantum.context': context.Context('', tenant_id)}
|
||||||
|
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||||
|
extra_environ=env)
|
||||||
|
quota = self.deserialize(res)
|
||||||
|
self.assertEqual(10, quota['quota']['network'])
|
||||||
|
self.assertEqual(10, quota['quota']['subnet'])
|
||||||
|
self.assertEqual(50, quota['quota']['port'])
|
||||||
|
self.assertEqual(-1, quota['quota']['extra1'])
|
||||||
|
|
||||||
|
def test_show_quotas_with_admin(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'quantum.context': context.Context('', tenant_id + '2',
|
||||||
|
is_admin=True)}
|
||||||
|
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||||
|
extra_environ=env)
|
||||||
|
self.assertEqual(200, res.status_int)
|
||||||
|
|
||||||
|
def test_show_quotas_without_admin_forbidden(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'quantum.context': context.Context('', tenant_id + '2',
|
||||||
|
is_admin=False)}
|
||||||
|
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||||
|
extra_environ=env, expect_errors=True)
|
||||||
|
self.assertEqual(403, res.status_int)
|
||||||
|
|
||||||
|
def test_update_quotas_forbidden(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
quotas = {'quota': {'network': 100}}
|
||||||
|
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||||
|
self.serialize(quotas),
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(403, res.status_int)
|
||||||
|
|
||||||
|
def test_delete_quotas_forbidden(self):
|
||||||
|
tenant_id = 'tenant_id1'
|
||||||
|
env = {'quantum.context': context.Context('', tenant_id,
|
||||||
|
is_admin=False)}
|
||||||
|
res = self.api.delete(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||||
|
extra_environ=env, expect_errors=True)
|
||||||
|
self.assertEqual(403, res.status_int)
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaExtensionCfgTestCaseXML(QuotaExtensionCfgTestCase):
|
||||||
|
fmt = 'xml'
|
||||||
|
Loading…
Reference in New Issue
Block a user