Better quota enforcement for GBP resources

This patch aligns the quota enforcement in GBP with the
changes made in Neutron quota management as a part of the
following blueprint and implementation patches referenced
therein:
https://blueprints.launchpad.net/neutron/+spec/better-quotas

The decorator @resource_registry.tracked_resources  in the
neutron.quota.resource_registry module is applied to the GBP
and Service Chain plugin __init__ methods.

In addition, the local_api module is also enhanced to enforce
quotas when GBP and Service Chain resources are created implicitly.

Older UTs that test the quotas have been preserved thus validating
the approach (they have only been moved to the appropriate test classes
on account of the resource tracking logic having moved from the earlier
DB modules to the plugin modules).

Closes-bug: 1594215

Change-Id: I38093426c89d1f4398c40da1f3392c0988831ff8
This commit is contained in:
Sumit Naiksatam 2016-06-19 01:43:56 -07:00
parent cc6141a1b2
commit 9519193d9c
12 changed files with 178 additions and 216 deletions

View File

@ -21,8 +21,10 @@ from neutron.extensions import securitygroup as ext_sg
from neutron import manager
from neutron.notifiers import nova
from neutron.plugins.common import constants as pconst
from neutron import quota
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from gbpservice.common import utils
from gbpservice.neutron.extensions import group_policy as gp_ext
@ -93,11 +95,35 @@ class LocalAPI(object):
do_notify=True):
# REVISIT(rkukura): Do create.start notification?
# REVISIT(rkukura): Check authorization?
# REVISIT(rkukura): Do quota?
with utils.clean_session(context.session):
reservation = None
if plugin in [self._group_policy_plugin,
self._servicechain_plugin]:
reservation = quota.QUOTAS.make_reservation(
context, context.tenant_id, {resource: 1}, plugin)
action = 'create_' + resource
obj_creator = getattr(plugin, action)
obj = obj_creator(context, {resource: attrs})
try:
obj = obj_creator(context, {resource: attrs})
except Exception:
# In case of failure the plugin will always raise an
# exception. Cancel the reservation
with excutils.save_and_reraise_exception():
if reservation:
quota.QUOTAS.cancel_reservation(
context, reservation.reservation_id)
if reservation:
quota.QUOTAS.commit_reservation(
context, reservation.reservation_id)
# At this point the implicit resource creation is successfull,
# so we should be calling:
# resource_registry.set_resources_dirty(context)
# to appropriately notify the quota engine. However, the above
# call begins a new transaction and we want to avoid that.
# Moreover, it can be safely assumed that any implicit resource
# creation via this local_api is always in response to an
# explicit resource creation request, and hence the above
# method will be invoked in the API layer.
if do_notify:
self._nova_notifier.send_network_change(action, {},
{resource: obj})

View File

@ -1,42 +0,0 @@
# 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 as nexcp
from neutron import context
from neutron.db import common_db_mixin
from neutron.db.quota import driver
from neutron.quota import resource as quota_resource
QUOTA_DRIVER = driver.DbQuotaDriver
DB_CLASS_TO_RESOURCE_NAMES = {}
class GBPQuotaBase(common_db_mixin.CommonDbMixin):
def __init__(self, *args, **kwargs):
super(GBPQuotaBase, self).__init__(*args, **kwargs)
tenant_id = kwargs['tenant_id']
ctx = context.Context(user_id=None, tenant_id=tenant_id)
class_name = self.__class__.__name__
resource = DB_CLASS_TO_RESOURCE_NAMES[class_name]
d = {resource: quota_resource.CountableResource(resource, None,
"quota_" + resource)}
resource_quota = QUOTA_DRIVER.get_tenant_quotas(ctx, d,
tenant_id)[resource]
if resource_quota == -1:
return
count = self._get_collection_count(ctx, self.__class__)
if count >= resource_quota:
raise nexcp.OverQuota(overs=[resource])

View File

@ -23,7 +23,6 @@ import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import exc
from gbpservice.neutron.db import gbp_quota_db as gquota
from gbpservice.neutron.extensions import group_policy as gpolicy
from gbpservice.neutron.services.grouppolicy.common import (
constants as gp_constants)
@ -46,8 +45,7 @@ class BaseSharedGbpResource(models_v2.HasId, models_v2.HasTenant,
pass
class PolicyTarget(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class PolicyTarget(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Lowest unit of abstraction on which a policy is applied."""
__tablename__ = 'gp_policy_targets'
type = sa.Column(sa.String(15))
@ -88,7 +86,7 @@ class PTGToPRSConsumingAssociation(model_base.BASEV2):
primary_key=True)
class PolicyTargetGroup(gquota.GBPQuotaBase, model_base.BASEV2,
class PolicyTargetGroup(model_base.BASEV2,
models_v2.HasId, models_v2.HasTenant):
"""It is a collection of policy_targets."""
__tablename__ = 'gp_policy_target_groups'
@ -117,8 +115,7 @@ class PolicyTargetGroup(gquota.GBPQuotaBase, model_base.BASEV2,
service_management = sa.Column(sa.Boolean)
class L2Policy(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class L2Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a L2 Policy for a collection of policy_target_groups."""
__tablename__ = 'gp_l2_policies'
type = sa.Column(sa.String(15))
@ -150,8 +147,7 @@ class ESToL3PAssociation(model_base.BASEV2):
primary_key=True)
class L3Policy(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class L3Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a L3 Policy with a non-overlapping IP address space."""
__tablename__ = 'gp_l3_policies'
type = sa.Column(sa.String(15))
@ -182,8 +178,8 @@ class NetworkServiceParam(model_base.BASEV2, models_v2.HasId):
nullable=False)
class NetworkServicePolicy(gquota.GBPQuotaBase, model_base.BASEV2,
models_v2.HasId, models_v2.HasTenant):
class NetworkServicePolicy(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
"""Represents a Network Service Policy."""
__tablename__ = 'gp_network_service_policies'
name = sa.Column(sa.String(255))
@ -219,8 +215,7 @@ class PolicyRuleActionAssociation(model_base.BASEV2):
primary_key=True)
class PolicyRule(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class PolicyRule(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a Group Policy Rule."""
__tablename__ = 'gp_policy_rules'
name = sa.Column(sa.String(255))
@ -239,7 +234,7 @@ class PolicyRule(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
shared = sa.Column(sa.Boolean)
class PolicyClassifier(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
class PolicyClassifier(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
"""Represents a Group Policy Classifier."""
__tablename__ = 'gp_policy_classifiers'
@ -257,8 +252,7 @@ class PolicyClassifier(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
shared = sa.Column(sa.Boolean)
class PolicyAction(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class PolicyAction(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a Group Policy Action."""
__tablename__ = 'gp_policy_actions'
name = sa.Column(sa.String(255))
@ -297,8 +291,7 @@ class EPToPRSConsumingAssociation(model_base.BASEV2):
primary_key=True)
class PolicyRuleSet(gquota.GBPQuotaBase, model_base.BASEV2,
models_v2.HasTenant):
class PolicyRuleSet(model_base.BASEV2, models_v2.HasTenant):
"""It is a collection of Policy rules."""
__tablename__ = 'gp_policy_rule_sets'
id = sa.Column(sa.String(36), primary_key=True,
@ -328,7 +321,7 @@ class PolicyRuleSet(gquota.GBPQuotaBase, model_base.BASEV2,
shared = sa.Column(sa.Boolean)
class NATPool(gquota.GBPQuotaBase, model_base.BASEV2, BaseSharedGbpResource):
class NATPool(model_base.BASEV2, BaseSharedGbpResource):
__tablename__ = 'gp_nat_pools'
type = sa.Column(sa.String(15))
__mapper_args__ = {
@ -362,8 +355,7 @@ class EPToESAssociation(model_base.BASEV2):
primary_key=True)
class ExternalSegment(gquota.GBPQuotaBase, model_base.BASEV2,
BaseSharedGbpResource):
class ExternalSegment(model_base.BASEV2, BaseSharedGbpResource):
__tablename__ = 'gp_external_segments'
type = sa.Column(sa.String(15))
__mapper_args__ = {
@ -385,8 +377,7 @@ class ExternalSegment(gquota.GBPQuotaBase, model_base.BASEV2,
cascade='all, delete-orphan')
class ExternalPolicy(gquota.GBPQuotaBase, model_base.BASEV2,
BaseSharedGbpResource):
class ExternalPolicy(model_base.BASEV2, BaseSharedGbpResource):
__tablename__ = 'gp_external_policies'
external_segments = orm.relationship(
EPToESAssociation,
@ -401,24 +392,6 @@ class ExternalPolicy(gquota.GBPQuotaBase, model_base.BASEV2,
cascade='all, delete-orphan')
gquota.DB_CLASS_TO_RESOURCE_NAMES[L3Policy.__name__] = 'l3_policy'
gquota.DB_CLASS_TO_RESOURCE_NAMES[L2Policy.__name__] = 'l2_policy'
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyTargetGroup.__name__] = (
'policy_target_group')
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyTarget.__name__] = 'policy_target'
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyClassifier.__name__] = (
'policy_classifier')
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyAction.__name__] = 'policy_action'
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyRule.__name__] = 'policy_rule'
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyRuleSet.__name__] = 'policy_rule_set'
gquota.DB_CLASS_TO_RESOURCE_NAMES[NetworkServicePolicy.__name__] = (
'network_service_policy')
gquota.DB_CLASS_TO_RESOURCE_NAMES[ExternalPolicy.__name__] = 'external_policy'
gquota.DB_CLASS_TO_RESOURCE_NAMES[ExternalSegment.__name__] = (
'external_segment')
gquota.DB_CLASS_TO_RESOURCE_NAMES[NATPool.__name__] = 'nat_pool'
class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
common_db_mixin.CommonDbMixin):
"""GroupPolicy plugin interface implementation using SQLAlchemy models."""

View File

@ -17,7 +17,6 @@ from oslo_utils import uuidutils
import sqlalchemy as sa
from sqlalchemy import orm
from gbpservice.neutron.db import gbp_quota_db as gquota
from gbpservice.neutron.db.grouppolicy import group_policy_db as gpdb
from gbpservice.neutron.extensions import group_policy as gpolicy
from gbpservice.neutron.services.grouppolicy.common import exceptions
@ -96,17 +95,6 @@ class NATPoolMapping(gpdb.NATPool):
nullable=True, unique=True)
gquota.DB_CLASS_TO_RESOURCE_NAMES[L3PolicyMapping.__name__] = 'l3_policy'
gquota.DB_CLASS_TO_RESOURCE_NAMES[L2PolicyMapping.__name__] = 'l2_policy'
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyTargetGroupMapping.__name__] = (
'policy_target_group')
gquota.DB_CLASS_TO_RESOURCE_NAMES[PolicyTargetMapping.__name__] = (
'policy_target')
gquota.DB_CLASS_TO_RESOURCE_NAMES[ExternalSegmentMapping.__name__] = (
'external_segment')
gquota.DB_CLASS_TO_RESOURCE_NAMES[NATPoolMapping.__name__] = 'nat_pool'
class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
"""Group Policy Mapping interface implementation using SQLAlchemy models.
"""

View File

@ -27,7 +27,6 @@ from sqlalchemy.ext.orderinglist import ordering_list
from sqlalchemy import orm
from sqlalchemy.orm import exc
from gbpservice.neutron.db import gbp_quota_db as gquota
from gbpservice.neutron.extensions import servicechain as schain
from gbpservice.neutron.services.servicechain.common import exceptions as s_exc
@ -59,7 +58,7 @@ class InstanceSpecAssociation(model_base.BASEV2):
position = sa.Column(sa.Integer)
class ServiceChainNode(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
class ServiceChainNode(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
"""ServiceChain Node"""
__tablename__ = 'sc_nodes'
@ -76,7 +75,7 @@ class ServiceChainNode(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
nullable=True)
class ServiceChainInstance(gquota.GBPQuotaBase, model_base.BASEV2,
class ServiceChainInstance(model_base.BASEV2,
models_v2.HasId, models_v2.HasTenant):
"""Service chain instances"""
__tablename__ = 'sc_instances'
@ -104,7 +103,7 @@ class ServiceChainInstance(gquota.GBPQuotaBase, model_base.BASEV2,
nullable=True)
class ServiceChainSpec(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
""" ServiceChain Spec
"""
@ -123,7 +122,7 @@ class ServiceChainSpec(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
shared = sa.Column(sa.Boolean)
class ServiceProfile(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
class ServiceProfile(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
""" Service Profile
"""
@ -140,16 +139,6 @@ class ServiceProfile(gquota.GBPQuotaBase, model_base.BASEV2, models_v2.HasId,
nodes = orm.relationship(ServiceChainNode, backref="service_profile")
gquota.DB_CLASS_TO_RESOURCE_NAMES[ServiceChainNode.__name__] = (
'servicechain_node')
gquota.DB_CLASS_TO_RESOURCE_NAMES[ServiceChainSpec.__name__] = (
'servicechain_spec')
gquota.DB_CLASS_TO_RESOURCE_NAMES[ServiceChainInstance.__name__] = (
'servicechain_instance')
gquota.DB_CLASS_TO_RESOURCE_NAMES[ServiceProfile.__name__] = (
'service_profile')
class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
common_db_mixin.CommonDbMixin):
"""ServiceChain plugin interface implementation using SQLAlchemy models."""

View File

@ -18,7 +18,6 @@ from neutron.api.v2 import resource_helper
from neutron.common import constants as n_constants
from neutron.common import exceptions as nexc
from neutron.plugins.common import constants
from neutron.quota import resource_registry
from neutron.services import service_base
from oslo_config import cfg
from oslo_log import log as logging
@ -870,16 +869,10 @@ class Group_policy(extensions.ExtensionDescriptor):
plural_mappings = resource_helper.build_plural_mappings(
special_mappings, RESOURCE_ATTRIBUTE_MAP)
attr.PLURALS.update(plural_mappings)
for resource_name in ['l3_policy', 'l2_policy', 'policy_target_group',
'policy_target', 'policy_classifier',
'policy_action', 'policy_rule',
'policy_rule_set', 'external_policy',
'external_segment', 'nat_pool',
'network_service_policy']:
resource_registry.register_resource_by_name(resource_name)
return resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.GROUP_POLICY)
constants.GROUP_POLICY,
register_quota=True)
@classmethod
def get_plugin_interface(cls):

View File

@ -17,7 +17,6 @@ from neutron.api.v2 import attributes as attr
from neutron.api.v2 import resource_helper
from neutron.common import exceptions as nexc
from neutron.plugins.common import constants
from neutron.quota import resource_registry
from neutron.services import service_base
from oslo_config import cfg
from oslo_log import log as logging
@ -278,12 +277,10 @@ class Servicechain(extensions.ExtensionDescriptor):
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
attr.PLURALS.update(plural_mappings)
for resource_name in ['servicechain_node', 'servicechain_spec',
'servicechain_instance', 'service_profile']:
resource_registry.register_resource_by_name(resource_name)
return resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.SERVICECHAIN)
constants.SERVICECHAIN,
register_quota=True)
@classmethod
def get_plugin_interface(cls):

View File

@ -19,6 +19,7 @@ from neutron import context as n_ctx
from neutron.extensions import portbindings
from neutron import manager as n_manager
from neutron.plugins.common import constants as pconst
from neutron.quota import resource_registry
from oslo_log import helpers as log
from oslo_log import log as logging
from oslo_utils import excutils
@ -336,6 +337,19 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
res_type=primary_type, res_id=primary['id'],
ref_type=reference_type, ref_id=reference['id'])
@resource_registry.tracked_resources(
l3_policy=group_policy_mapping_db.L3PolicyMapping,
l2_policy=group_policy_mapping_db.L2PolicyMapping,
policy_target=group_policy_mapping_db.PolicyTargetMapping,
policy_target_group=group_policy_mapping_db.PolicyTargetGroupMapping,
policy_classifier=gpdb.PolicyClassifier,
policy_action=gpdb.PolicyAction,
policy_rule=gpdb.PolicyRule,
policy_rule_set=gpdb.PolicyRuleSet,
external_policy=gpdb.ExternalPolicy,
external_segment=group_policy_mapping_db.ExternalSegmentMapping,
nat_pool=group_policy_mapping_db.NATPoolMapping,
network_service_policy=gpdb.NetworkServicePolicy)
def __init__(self):
self.extension_manager = ext_manager.ExtensionManager()
self.policy_driver_manager = manager.PolicyDriverManager()

View File

@ -13,6 +13,7 @@
from neutron._i18n import _LE
from neutron._i18n import _LI
from neutron.plugins.common import constants as pconst
from neutron.quota import resource_registry
from oslo_config import cfg
from oslo_log import helpers as log
from oslo_log import log as logging
@ -43,6 +44,11 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
supported_extension_aliases = ["servicechain"]
path_prefix = gp_cts.GBP_PREFIXES[pconst.SERVICECHAIN]
@resource_registry.tracked_resources(
servicechain_node=servicechain_db.ServiceChainNode,
servicechain_spec=servicechain_db.ServiceChainSpec,
servicechain_instance=servicechain_db.ServiceChainInstance,
service_profile=servicechain_db.ServiceProfile)
def __init__(self):
self.driver_manager = manager.NodeDriverManager()
super(NodeCompositionPlugin, self).__init__()

View File

@ -24,7 +24,6 @@ from neutron.plugins.common import constants
from neutron import policy
from neutron.tests.unit.api import test_extensions
from neutron.tests.unit.db import test_db_base_plugin_v2
from oslo_config import cfg
from oslo_utils import importutils
from oslo_utils import uuidutils
@ -1539,93 +1538,3 @@ class TestGroupResources(GroupPolicyDbTestCase):
expected_res_status=400)
self.assertEqual('IpAddressOverlappingInExternalSegment',
res['NeutronError']['type'])
class TestQuotasForGBP(GroupPolicyDbTestCase):
def setUp(self, core_plugin=None, gp_plugin=None, service_plugins=None,
ext_mgr=None):
cfg.CONF.set_override('quota_l3_policy', 1, group='QUOTAS')
cfg.CONF.set_override('quota_l2_policy', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target_group', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_action', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_classifier', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule_set', 1, group='QUOTAS')
cfg.CONF.set_override('quota_network_service_policy', 1,
group='QUOTAS')
cfg.CONF.set_override('quota_external_policy', 1, group='QUOTAS')
cfg.CONF.set_override('quota_external_segment', 1, group='QUOTAS')
cfg.CONF.set_override('quota_nat_pool', 1, group='QUOTAS')
super(TestQuotasForGBP, self).setUp(
core_plugin=core_plugin, gp_plugin=gp_plugin,
service_plugins=service_plugins, ext_mgr=ext_mgr)
def tearDown(self):
cfg.CONF.set_override('quota_l3_policy', -1, group='QUOTAS')
cfg.CONF.set_override('quota_l2_policy', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target_group', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_action', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_classifier', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule_set', -1, group='QUOTAS')
cfg.CONF.set_override('quota_network_service_policy', -1,
group='QUOTAS')
cfg.CONF.set_override('quota_external_policy', -1, group='QUOTAS')
cfg.CONF.set_override('quota_external_segment', -1, group='QUOTAS')
cfg.CONF.set_override('quota_nat_pool', -1, group='QUOTAS')
super(TestQuotasForGBP, self).tearDown()
def test_group_resources_quota(self):
ptg_id = self.create_policy_target_group()['policy_target_group']['id']
self.create_policy_target(policy_target_group_id=ptg_id)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_target,
policy_target_group_id=ptg_id)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_target_group)
def test_l3policy_quota(self):
self.create_l3_policy()
self.assertRaises(webob.exc.HTTPClientError,
self.create_l3_policy)
def test_l2policy_quota(self):
self.create_l2_policy()
self.assertRaises(webob.exc.HTTPClientError,
self.create_l2_policy)
def test_policy_resources_quota(self):
pa_id = self.create_policy_action()['policy_action']['id']
pc_id = self.create_policy_classifier()['policy_classifier']['id']
pr_id = self.create_policy_rule(
policy_classifier_id=pc_id,
policy_actions=[pa_id])['policy_rule']['id']
self.create_policy_rule_set(policy_rules=[pr_id])
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_action)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_classifier)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_rule,
policy_classifier_id=pc_id,
policy_actions=[pa_id])
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_rule_set,
policy_rules=[pr_id])
self.create_network_service_policy()
self.assertRaises(webob.exc.HTTPClientError,
self.create_network_service_policy)
def test_external_connectivity_resources_quota(self):
self.create_external_policy()
self.create_external_segment()
self.create_nat_pool()
self.assertRaises(webob.exc.HTTPClientError,
self.create_external_policy)
self.assertRaises(webob.exc.HTTPClientError,
self.create_external_segment)
self.assertRaises(webob.exc.HTTPClientError,
self.create_nat_pool)

View File

@ -974,3 +974,91 @@ class TestGroupPolicyPluginMappedGroupResourceAttrs(
GroupPolicyPluginTestCase, tgpmdb.TestMappedGroupResourceAttrs):
pass
class TestQuotasForGBP(GroupPolicyPluginTestCase):
def setUp(self, core_plugin=None, gp_plugin=None):
cfg.CONF.set_override('quota_l3_policy', 1, group='QUOTAS')
cfg.CONF.set_override('quota_l2_policy', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target_group', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_action', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_classifier', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule', 1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule_set', 1, group='QUOTAS')
cfg.CONF.set_override('quota_network_service_policy', 1,
group='QUOTAS')
cfg.CONF.set_override('quota_external_policy', 1, group='QUOTAS')
cfg.CONF.set_override('quota_external_segment', 1, group='QUOTAS')
cfg.CONF.set_override('quota_nat_pool', 1, group='QUOTAS')
super(TestQuotasForGBP, self).setUp(
core_plugin=core_plugin, gp_plugin=gp_plugin)
def tearDown(self):
cfg.CONF.set_override('quota_l3_policy', -1, group='QUOTAS')
cfg.CONF.set_override('quota_l2_policy', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target_group', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_target', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_action', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_classifier', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule', -1, group='QUOTAS')
cfg.CONF.set_override('quota_policy_rule_set', -1, group='QUOTAS')
cfg.CONF.set_override('quota_network_service_policy', -1,
group='QUOTAS')
cfg.CONF.set_override('quota_external_policy', -1, group='QUOTAS')
cfg.CONF.set_override('quota_external_segment', -1, group='QUOTAS')
cfg.CONF.set_override('quota_nat_pool', -1, group='QUOTAS')
super(TestQuotasForGBP, self).tearDown()
def test_group_resources_quota(self):
ptg_id = self.create_policy_target_group()['policy_target_group']['id']
self.create_policy_target(policy_target_group_id=ptg_id)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_target,
policy_target_group_id=ptg_id)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_target_group)
def test_l3policy_quota(self):
self.create_l3_policy()
self.assertRaises(webob.exc.HTTPClientError,
self.create_l3_policy)
def test_l2policy_quota(self):
self.create_l2_policy()
self.assertRaises(webob.exc.HTTPClientError,
self.create_l2_policy)
def test_policy_resources_quota(self):
pa_id = self.create_policy_action()['policy_action']['id']
pc_id = self.create_policy_classifier()['policy_classifier']['id']
pr_id = self.create_policy_rule(
policy_classifier_id=pc_id,
policy_actions=[pa_id])['policy_rule']['id']
self.create_policy_rule_set(policy_rules=[pr_id])
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_action)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_classifier)
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_rule,
policy_classifier_id=pc_id,
policy_actions=[pa_id])
self.assertRaises(webob.exc.HTTPClientError,
self.create_policy_rule_set,
policy_rules=[pr_id])
self.create_network_service_policy()
self.assertRaises(webob.exc.HTTPClientError,
self.create_network_service_policy)
def test_external_connectivity_resources_quota(self):
self.create_external_policy()
self.create_external_segment()
self.create_nat_pool()
self.assertRaises(webob.exc.HTTPClientError,
self.create_external_policy)
self.assertRaises(webob.exc.HTTPClientError,
self.create_external_segment)
self.assertRaises(webob.exc.HTTPClientError,
self.create_nat_pool)

View File

@ -819,6 +819,27 @@ class TestQuotasForServiceChain(test_base.ServiceChainPluginTestCase):
group='QUOTAS')
super(TestQuotasForServiceChain, self).tearDown()
def test_servicechain_node_quota(self):
self.create_servicechain_node()
self.assertRaises(webob.exc.HTTPClientError,
self.create_servicechain_node)
def test_servicechain_spec_quota(self):
self.create_servicechain_spec()
self.assertRaises(webob.exc.HTTPClientError,
self.create_servicechain_spec)
def test_servicechain_instance_quota(self):
self.create_servicechain_instance()
self.assertRaises(webob.exc.HTTPClientError,
self.create_servicechain_instance)
def test_service_profile(self):
self.create_service_profile(service_type=pconst.FIREWALL)
self.assertRaises(webob.exc.HTTPClientError,
self.create_service_profile,
service_type=pconst.FIREWALL)
def test_quota_implicit_service_instance(self):
prof = self.create_service_profile(
service_type='LOADBALANCER',