Merge "Create packages for quota modules"
This commit is contained in:
commit
50d662d95a
|
@ -593,7 +593,7 @@
|
|||
|
||||
[quotas]
|
||||
# Default driver to use for quota checks
|
||||
# quota_driver = neutron.db.quota_db.DbQuotaDriver
|
||||
# quota_driver = neutron.db.quota.driver.DbQuotaDriver
|
||||
|
||||
# Resource name(s) that are supported in quota features
|
||||
# This option is deprecated for removal in the M release, please refrain from using it
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
# Copyright 2011 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.common import exceptions
|
||||
from neutron.db.quota import models as quota_models
|
||||
|
||||
|
||||
class DbQuotaDriver(object):
|
||||
"""Driver to perform necessary checks to enforce quotas and obtain quota
|
||||
information.
|
||||
|
||||
The default driver utilizes the local database.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_tenant_quotas(context, resources, tenant_id):
|
||||
"""Given a list of resources, retrieve the quotas for the given
|
||||
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 quotas for.
|
||||
:return dict: from resource name to dict of name and limit
|
||||
"""
|
||||
|
||||
# init with defaults
|
||||
tenant_quota = dict((key, resource.default)
|
||||
for key, resource in resources.items())
|
||||
|
||||
# update with tenant specific limits
|
||||
q_qry = context.session.query(quota_models.Quota).filter_by(
|
||||
tenant_id=tenant_id)
|
||||
tenant_quota.update((q['resource'], q['limit']) for q in q_qry)
|
||||
|
||||
return tenant_quota
|
||||
|
||||
@staticmethod
|
||||
def delete_tenant_quota(context, tenant_id):
|
||||
"""Delete the quota entries for a given tenant_id.
|
||||
|
||||
Atfer deletion, this tenant will use default quota values in conf.
|
||||
"""
|
||||
with context.session.begin():
|
||||
tenant_quotas = context.session.query(quota_models.Quota)
|
||||
tenant_quotas = tenant_quotas.filter_by(tenant_id=tenant_id)
|
||||
tenant_quotas.delete()
|
||||
|
||||
@staticmethod
|
||||
def get_all_quotas(context, resources):
|
||||
"""Given a list of resources, retrieve the quotas for the all tenants.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param resources: A dictionary of the registered resource keys.
|
||||
:return quotas: list of dict of tenant_id:, resourcekey1:
|
||||
resourcekey2: ...
|
||||
"""
|
||||
tenant_default = dict((key, resource.default)
|
||||
for key, resource in resources.items())
|
||||
|
||||
all_tenant_quotas = {}
|
||||
|
||||
for quota in context.session.query(quota_models.Quota):
|
||||
tenant_id = quota['tenant_id']
|
||||
|
||||
# avoid setdefault() because only want to copy when actually req'd
|
||||
tenant_quota = all_tenant_quotas.get(tenant_id)
|
||||
if tenant_quota is None:
|
||||
tenant_quota = tenant_default.copy()
|
||||
tenant_quota['tenant_id'] = tenant_id
|
||||
all_tenant_quotas[tenant_id] = tenant_quota
|
||||
|
||||
tenant_quota[quota['resource']] = quota['limit']
|
||||
|
||||
return list(all_tenant_quotas.values())
|
||||
|
||||
@staticmethod
|
||||
def update_quota_limit(context, tenant_id, resource, limit):
|
||||
with context.session.begin():
|
||||
tenant_quota = context.session.query(quota_models.Quota).filter_by(
|
||||
tenant_id=tenant_id, resource=resource).first()
|
||||
|
||||
if tenant_quota:
|
||||
tenant_quota.update({'limit': limit})
|
||||
else:
|
||||
tenant_quota = quota_models.Quota(tenant_id=tenant_id,
|
||||
resource=resource,
|
||||
limit=limit)
|
||||
context.session.add(tenant_quota)
|
||||
|
||||
def _get_quotas(self, context, tenant_id, resources):
|
||||
"""Retrieves the quotas for specific resources.
|
||||
|
||||
A helper method which retrieves the quotas for the specific
|
||||
resources identified by keys, and which apply to the current
|
||||
context.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param tenant_id: the tenant_id to check quota.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
"""
|
||||
# Grab and return the quotas (without usages)
|
||||
quotas = DbQuotaDriver.get_tenant_quotas(
|
||||
context, resources, tenant_id)
|
||||
|
||||
return dict((k, v) for k, v in quotas.items())
|
||||
|
||||
def limit_check(self, context, tenant_id, resources, values):
|
||||
"""Check simple quota limits.
|
||||
|
||||
For limits--those quotas for which there is no usage
|
||||
synchronization function--this method checks that a set of
|
||||
proposed values are permitted by the limit restriction.
|
||||
|
||||
If any of the proposed values is over the defined quota, an
|
||||
OverQuota exception will be raised with the sorted list of the
|
||||
resources which are too high. Otherwise, the method returns
|
||||
nothing.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param tenant_id: The tenant_id to check the quota.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
:param values: A dictionary of the values to check against the
|
||||
quota.
|
||||
"""
|
||||
|
||||
# Ensure no value is less than zero
|
||||
unders = [key for key, val in values.items() if val < 0]
|
||||
if unders:
|
||||
raise exceptions.InvalidQuotaValue(unders=sorted(unders))
|
||||
|
||||
# Get the applicable quotas
|
||||
quotas = self._get_quotas(context, tenant_id, resources)
|
||||
|
||||
# Check the quotas and construct a list of the resources that
|
||||
# would be put over limit by the desired values
|
||||
overs = [key for key, val in values.items()
|
||||
if quotas[key] >= 0 and quotas[key] < val]
|
||||
if overs:
|
||||
raise exceptions.OverQuota(overs=sorted(overs))
|
|
@ -13,139 +13,10 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.common import exceptions
|
||||
from neutron.db.quota import models as quota_models
|
||||
import sys
|
||||
|
||||
from neutron.db.quota import driver # noqa
|
||||
|
||||
class DbQuotaDriver(object):
|
||||
"""Driver to perform necessary checks to enforce quotas and obtain quota
|
||||
information.
|
||||
|
||||
The default driver utilizes the local database.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_tenant_quotas(context, resources, tenant_id):
|
||||
"""Given a list of resources, retrieve the quotas for the given
|
||||
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 quotas for.
|
||||
:return dict: from resource name to dict of name and limit
|
||||
"""
|
||||
|
||||
# init with defaults
|
||||
tenant_quota = dict((key, resource.default)
|
||||
for key, resource in resources.items())
|
||||
|
||||
# update with tenant specific limits
|
||||
q_qry = context.session.query(quota_models.Quota).filter_by(
|
||||
tenant_id=tenant_id)
|
||||
tenant_quota.update((q['resource'], q['limit']) for q in q_qry)
|
||||
|
||||
return tenant_quota
|
||||
|
||||
@staticmethod
|
||||
def delete_tenant_quota(context, tenant_id):
|
||||
"""Delete the quota entries for a given tenant_id.
|
||||
|
||||
Atfer deletion, this tenant will use default quota values in conf.
|
||||
"""
|
||||
with context.session.begin():
|
||||
tenant_quotas = context.session.query(quota_models.Quota)
|
||||
tenant_quotas = tenant_quotas.filter_by(tenant_id=tenant_id)
|
||||
tenant_quotas.delete()
|
||||
|
||||
@staticmethod
|
||||
def get_all_quotas(context, resources):
|
||||
"""Given a list of resources, retrieve the quotas for the all tenants.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param resources: A dictionary of the registered resource keys.
|
||||
:return quotas: list of dict of tenant_id:, resourcekey1:
|
||||
resourcekey2: ...
|
||||
"""
|
||||
tenant_default = dict((key, resource.default)
|
||||
for key, resource in resources.items())
|
||||
|
||||
all_tenant_quotas = {}
|
||||
|
||||
for quota in context.session.query(quota_models.Quota):
|
||||
tenant_id = quota['tenant_id']
|
||||
|
||||
# avoid setdefault() because only want to copy when actually req'd
|
||||
tenant_quota = all_tenant_quotas.get(tenant_id)
|
||||
if tenant_quota is None:
|
||||
tenant_quota = tenant_default.copy()
|
||||
tenant_quota['tenant_id'] = tenant_id
|
||||
all_tenant_quotas[tenant_id] = tenant_quota
|
||||
|
||||
tenant_quota[quota['resource']] = quota['limit']
|
||||
|
||||
return list(all_tenant_quotas.values())
|
||||
|
||||
@staticmethod
|
||||
def update_quota_limit(context, tenant_id, resource, limit):
|
||||
with context.session.begin():
|
||||
tenant_quota = context.session.query(quota_models.Quota).filter_by(
|
||||
tenant_id=tenant_id, resource=resource).first()
|
||||
|
||||
if tenant_quota:
|
||||
tenant_quota.update({'limit': limit})
|
||||
else:
|
||||
tenant_quota = quota_models.Quota(tenant_id=tenant_id,
|
||||
resource=resource,
|
||||
limit=limit)
|
||||
context.session.add(tenant_quota)
|
||||
|
||||
def _get_quotas(self, context, tenant_id, resources):
|
||||
"""Retrieves the quotas for specific resources.
|
||||
|
||||
A helper method which retrieves the quotas for the specific
|
||||
resources identified by keys, and which apply to the current
|
||||
context.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param tenant_id: the tenant_id to check quota.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
"""
|
||||
# Grab and return the quotas (without usages)
|
||||
quotas = DbQuotaDriver.get_tenant_quotas(
|
||||
context, resources, tenant_id)
|
||||
|
||||
return dict((k, v) for k, v in quotas.items())
|
||||
|
||||
def limit_check(self, context, tenant_id, resources, values):
|
||||
"""Check simple quota limits.
|
||||
|
||||
For limits--those quotas for which there is no usage
|
||||
synchronization function--this method checks that a set of
|
||||
proposed values are permitted by the limit restriction.
|
||||
|
||||
If any of the proposed values is over the defined quota, an
|
||||
OverQuota exception will be raised with the sorted list of the
|
||||
resources which are too high. Otherwise, the method returns
|
||||
nothing.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param tenant_id: The tenant_id to check the quota.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
:param values: A dictionary of the values to check against the
|
||||
quota.
|
||||
"""
|
||||
|
||||
# Ensure no value is less than zero
|
||||
unders = [key for key, val in values.items() if val < 0]
|
||||
if unders:
|
||||
raise exceptions.InvalidQuotaValue(unders=sorted(unders))
|
||||
|
||||
# Get the applicable quotas
|
||||
quotas = self._get_quotas(context, tenant_id, resources)
|
||||
|
||||
# Check the quotas and construct a list of the resources that
|
||||
# would be put over limit by the desired values
|
||||
overs = [key for key, val in values.items()
|
||||
if quotas[key] >= 0 and quotas[key] < val]
|
||||
if overs:
|
||||
raise exceptions.OverQuota(overs=sorted(overs))
|
||||
# This module has been preserved for backward compatibility, and will be
|
||||
# deprecated in the future
|
||||
sys.modules[__name__] = sys.modules['neutron.db.quota.driver']
|
||||
|
|
|
@ -31,7 +31,7 @@ from neutron import wsgi
|
|||
RESOURCE_NAME = 'quota'
|
||||
RESOURCE_COLLECTION = RESOURCE_NAME + "s"
|
||||
QUOTAS = quota.QUOTAS
|
||||
DB_QUOTA_DRIVER = 'neutron.db.quota_db.DbQuotaDriver'
|
||||
DB_QUOTA_DRIVER = 'neutron.db.quota.driver.DbQuotaDriver'
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
RESOURCE_COLLECTION: {}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ from neutron.db import agentschedulers_db
|
|||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import external_net_db
|
||||
from neutron.db import portbindings_db
|
||||
from neutron.db import quota_db
|
||||
from neutron.db.quota import driver
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.extensions import providernet
|
||||
from neutron.i18n import _LW
|
||||
|
@ -59,7 +59,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
n1kv_db_v2.PolicyProfile_db_mixin,
|
||||
network_db_v2.Credential_db_mixin,
|
||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||
quota_db.DbQuotaDriver):
|
||||
driver.DbQuotaDriver):
|
||||
|
||||
"""
|
||||
Implement the Neutron abstractions using Cisco Nexus1000V.
|
||||
|
|
|
@ -31,7 +31,6 @@ from neutron.db import db_base_plugin_v2
|
|||
from neutron.db import external_net_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
from neutron.db import portbindings_db
|
||||
from neutron.db import quota_db # noqa
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.i18n import _LE, _LI, _LW
|
||||
from neutron.plugins.ibm.common import config # noqa
|
||||
|
|
|
@ -54,7 +54,7 @@ from neutron.db import external_net_db
|
|||
from neutron.db import extradhcpopt_db
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import netmtu_db
|
||||
from neutron.db import quota_db # noqa
|
||||
from neutron.db.quota import driver # noqa
|
||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||
from neutron.db import vlantransparent_db
|
||||
from neutron.extensions import allowedaddresspairs as addr_pair
|
||||
|
|
|
@ -39,7 +39,6 @@ from neutron.db import extraroute_db
|
|||
from neutron.db import l3_agentschedulers_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
from neutron.db import portbindings_base
|
||||
from neutron.db import quota_db # noqa
|
||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.i18n import _LE
|
||||
|
|
|
@ -28,8 +28,8 @@ from neutron.i18n import _LI, _LW
|
|||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
QUOTA_DB_MODULE = 'neutron.db.quota_db'
|
||||
QUOTA_DB_DRIVER = 'neutron.db.quota_db.DbQuotaDriver'
|
||||
QUOTA_DB_MODULE = 'neutron.db.quota.driver'
|
||||
QUOTA_DB_DRIVER = '%s.DbQuotaDriver' % QUOTA_DB_MODULE
|
||||
QUOTA_CONF_DRIVER = 'neutron.quota.ConfDriver'
|
||||
default_quota_items = ['network', 'subnet', 'port']
|
||||
|
||||
|
@ -226,8 +226,8 @@ class QuotaEngine(object):
|
|||
versionutils.report_deprecated_feature(
|
||||
LOG, _LW("The quota driver neutron.quota.ConfDriver is "
|
||||
"deprecated as of Liberty. "
|
||||
"neutron.db.quota_db.DbQuotaDriver should be "
|
||||
"used in its place"))
|
||||
"neutron.db.quota.driver.DbQuotaDriver should "
|
||||
"be used in its place"))
|
||||
self._driver = _driver_class
|
||||
LOG.info(_LI('Loaded quota_driver: %s.'), _driver_class)
|
||||
return self._driver
|
|
@ -35,7 +35,7 @@ class QuotasTest(base.BaseAdminNetworkTest):
|
|||
It is also assumed that the per-tenant quota extension API is configured
|
||||
in /etc/neutron/neutron.conf as follows:
|
||||
|
||||
quota_driver = neutron.db.quota_db.DbQuotaDriver
|
||||
quota_driver = neutron.db.driver.DbQuotaDriver
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
from neutron.common import exceptions
|
||||
from neutron import context
|
||||
from neutron.db import db_base_plugin_v2 as base_plugin
|
||||
from neutron.db import quota_db
|
||||
from neutron.db.quota import driver
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
class FakePlugin(base_plugin.NeutronDbPluginV2, quota_db.DbQuotaDriver):
|
||||
class FakePlugin(base_plugin.NeutronDbPluginV2, driver.DbQuotaDriver):
|
||||
"""A fake plugin class containing all DB methods."""
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ from neutron.common import config
|
|||
from neutron.common import constants
|
||||
from neutron.common import exceptions
|
||||
from neutron import context
|
||||
from neutron.db import quota_db
|
||||
from neutron.db.quota import driver
|
||||
from neutron import quota
|
||||
from neutron.tests import base
|
||||
from neutron.tests import tools
|
||||
|
@ -95,7 +95,7 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
|
|||
def setUp(self):
|
||||
cfg.CONF.set_override(
|
||||
'quota_driver',
|
||||
'neutron.db.quota_db.DbQuotaDriver',
|
||||
'neutron.db.quota.driver.DbQuotaDriver',
|
||||
group='QUOTAS')
|
||||
super(QuotaExtensionDbTestCase, self).setUp()
|
||||
|
||||
|
@ -404,25 +404,25 @@ class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
|
|||
|
||||
|
||||
class TestDbQuotaDriver(base.BaseTestCase):
|
||||
"""Test for neutron.db.quota_db.DbQuotaDriver."""
|
||||
"""Test for neutron.db.quota.driver.DbQuotaDriver."""
|
||||
|
||||
def test_get_tenant_quotas_arg(self):
|
||||
"""Call neutron.db.quota_db.DbQuotaDriver._get_quotas."""
|
||||
"""Call neutron.db.quota.driver.DbQuotaDriver._get_quotas."""
|
||||
|
||||
driver = quota_db.DbQuotaDriver()
|
||||
quota_driver = driver.DbQuotaDriver()
|
||||
ctx = context.Context('', 'bar')
|
||||
|
||||
foo_quotas = {'network': 5}
|
||||
default_quotas = {'network': 10}
|
||||
target_tenant = 'foo'
|
||||
|
||||
with mock.patch.object(quota_db.DbQuotaDriver,
|
||||
with mock.patch.object(driver.DbQuotaDriver,
|
||||
'get_tenant_quotas',
|
||||
return_value=foo_quotas) as get_tenant_quotas:
|
||||
|
||||
quotas = driver._get_quotas(ctx,
|
||||
target_tenant,
|
||||
default_quotas)
|
||||
quotas = quota_driver._get_quotas(ctx,
|
||||
target_tenant,
|
||||
default_quotas)
|
||||
|
||||
self.assertEqual(quotas, foo_quotas)
|
||||
get_tenant_quotas.assert_called_once_with(ctx,
|
||||
|
@ -441,17 +441,17 @@ class TestQuotaDriverLoad(base.BaseTestCase):
|
|||
cfg.CONF.set_override('quota_driver', cfg_driver, group='QUOTAS')
|
||||
with mock.patch.dict(sys.modules, {}):
|
||||
if (not with_quota_db_module and
|
||||
'neutron.db.quota_db' in sys.modules):
|
||||
del sys.modules['neutron.db.quota_db']
|
||||
'neutron.db.quota.driver' in sys.modules):
|
||||
del sys.modules['neutron.db.quota.driver']
|
||||
driver = quota.QUOTAS.get_driver()
|
||||
self.assertEqual(loaded_driver, driver.__class__.__name__)
|
||||
|
||||
def test_quota_db_driver_with_quotas_table(self):
|
||||
self._test_quota_driver('neutron.db.quota_db.DbQuotaDriver',
|
||||
self._test_quota_driver('neutron.db.quota.driver.DbQuotaDriver',
|
||||
'DbQuotaDriver', True)
|
||||
|
||||
def test_quota_db_driver_fallback_conf_driver(self):
|
||||
self._test_quota_driver('neutron.db.quota_db.DbQuotaDriver',
|
||||
self._test_quota_driver('neutron.db.quota.driver.DbQuotaDriver',
|
||||
'ConfDriver', False)
|
||||
|
||||
def test_quota_conf_driver(self):
|
||||
|
|
2
tox.ini
2
tox.ini
|
@ -160,7 +160,7 @@ commands = python -m testtools.run \
|
|||
neutron.tests.unit.db.test_l3_hamode_db \
|
||||
neutron.tests.unit.db.test_migration \
|
||||
neutron.tests.unit.db.test_agents_db \
|
||||
neutron.tests.unit.db.test_quota_db \
|
||||
neutron.tests.unit.db.quota.test_driver \
|
||||
neutron.tests.unit.db.test_dvr_mac_db \
|
||||
neutron.tests.unit.debug.test_commands \
|
||||
neutron.tests.unit.tests.test_post_mortem_debug \
|
||||
|
|
Loading…
Reference in New Issue