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:
parent
cc6141a1b2
commit
9519193d9c
@ -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})
|
||||
|
@ -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])
|
@ -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."""
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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."""
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -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__()
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user