[QoS] Add rule type packet per second (pps)
This patch adds new API extension to QoS service plugin to allow CURD actions for packet rate limit (packet per second) rule in Neutron server side. NOTE: This patch will NOT implement the real functionality in L2/L3 backend to limit the pps. Co-Authored-By: NANALI <lin203@chinaunicom.cn> Closes-bug: #1912460 Change-Id: Icc88accb88d9cec40c960c56f032c3c27317b42e
This commit is contained in:
parent
b7befc9811
commit
8e30639452
@ -1 +1 @@
|
||||
8df53b0d2c0e
|
||||
1bb3393de75d
|
||||
|
@ -0,0 +1,55 @@
|
||||
# Copyright (c) 2021 China Unicom Cloud Data Co.,Ltd.
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""add qos policy rule Packet Rate Limit
|
||||
|
||||
Revision ID: 1bb3393de75d
|
||||
Revises: 8df53b0d2c0e
|
||||
Create Date: 2021-01-22 17:00:03.085196
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
from neutron_lib import constants
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '1bb3393de75d'
|
||||
down_revision = '8df53b0d2c0e'
|
||||
|
||||
direction_enum = sa.Enum(
|
||||
constants.EGRESS_DIRECTION, constants.INGRESS_DIRECTION,
|
||||
name='qos_packet_rate_limit_rules_directions'
|
||||
)
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'qos_packet_rate_limit_rules',
|
||||
sa.Column('id', sa.String(36), primary_key=True),
|
||||
sa.Column('qos_policy_id',
|
||||
sa.String(length=36),
|
||||
sa.ForeignKey('qos_policies.id', ondelete='CASCADE'),
|
||||
nullable=False, index=True),
|
||||
sa.Column('max_kpps', sa.Integer()),
|
||||
sa.Column('max_burst_kpps', sa.Integer()),
|
||||
sa.Column('direction', direction_enum,
|
||||
nullable=False,
|
||||
server_default=constants.EGRESS_DIRECTION),
|
||||
sa.UniqueConstraint('qos_policy_id', 'direction',
|
||||
name='qos_packet_rate_limit_rules0qos_policy_id0direction')
|
||||
)
|
@ -192,3 +192,29 @@ class QosMinimumBandwidthRule(model_base.HasId, model_base.BASEV2):
|
||||
name='qos_minimum_bandwidth_rules0qos_policy_id0direction'),
|
||||
model_base.BASEV2.__table_args__
|
||||
)
|
||||
|
||||
|
||||
class QosPacketRateLimitRule(model_base.HasId, model_base.BASEV2):
|
||||
__tablename__ = 'qos_packet_rate_limit_rules'
|
||||
qos_policy_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('qos_policies.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False,
|
||||
index=True)
|
||||
max_kpps = sa.Column(sa.Integer)
|
||||
max_burst_kpps = sa.Column(sa.Integer)
|
||||
revises_on_change = ('qos_policy',)
|
||||
qos_policy = sa.orm.relationship(QosPolicy, load_on_pending=True)
|
||||
direction = sa.Column(
|
||||
sa.Enum(constants.EGRESS_DIRECTION,
|
||||
constants.INGRESS_DIRECTION,
|
||||
name="qos_packet_rate_limit_rules_directions"),
|
||||
default=constants.EGRESS_DIRECTION,
|
||||
server_default=constants.EGRESS_DIRECTION,
|
||||
nullable=False)
|
||||
__table_args__ = (
|
||||
sa.UniqueConstraint(
|
||||
qos_policy_id, direction,
|
||||
name="qos_packet_rate_limit_rules0qos_policy_id0direction"),
|
||||
model_base.BASEV2.__table_args__
|
||||
)
|
||||
|
@ -84,9 +84,12 @@ class QoSPluginBase(service_base.ServicePluginBase, metaclass=abc.ABCMeta):
|
||||
path_prefix = apidef.API_PREFIX
|
||||
|
||||
# The rule object type to use for each incoming rule-related request.
|
||||
rule_objects = {'bandwidth_limit': rule_object.QosBandwidthLimitRule,
|
||||
'dscp_marking': rule_object.QosDscpMarkingRule,
|
||||
'minimum_bandwidth': rule_object.QosMinimumBandwidthRule}
|
||||
rule_objects = {
|
||||
'bandwidth_limit': rule_object.QosBandwidthLimitRule,
|
||||
'dscp_marking': rule_object.QosDscpMarkingRule,
|
||||
'minimum_bandwidth': rule_object.QosMinimumBandwidthRule,
|
||||
'packet_rate_limit': rule_object.QosPacketRateLimitRule,
|
||||
}
|
||||
|
||||
# Patterns used to call method proxies for all policy-rule-specific
|
||||
# method calls (see __getattr__ docstring, below).
|
||||
|
60
neutron/extensions/qos_pps_rule.py
Normal file
60
neutron/extensions/qos_pps_rule.py
Normal file
@ -0,0 +1,60 @@
|
||||
# Copyright (c) 2021 China Unicom Cloud Data Co.,Ltd.
|
||||
# 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_lib.api.definitions import qos_bw_minimum_ingress
|
||||
from neutron_lib.api.definitions import qos_pps_rule as apidef
|
||||
from neutron_lib.api import extensions as api_extensions
|
||||
from neutron_lib.plugins import constants
|
||||
from neutron_lib.plugins import directory
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import base
|
||||
|
||||
COLLECTION_NAME = 'packet_rate_limit_rules'
|
||||
RESOURCE_NAME = 'packet_rate_limit_rule'
|
||||
|
||||
# A quick align for subresource minimum bandwidth ingress direction.
|
||||
# TODO(liuyulong): Move to neutron-lib
|
||||
apidef.SUB_RESOURCE_ATTRIBUTE_MAP.update(
|
||||
qos_bw_minimum_ingress.SUB_RESOURCE_ATTRIBUTE_MAP)
|
||||
|
||||
|
||||
class Qos_pps_rule(api_extensions.APIExtensionDescriptor):
|
||||
|
||||
api_definition = apidef
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
plugin = directory.get_plugin(constants.QOS)
|
||||
params = apidef.SUB_RESOURCE_ATTRIBUTE_MAP[
|
||||
COLLECTION_NAME]['parameters']
|
||||
parent = apidef.SUB_RESOURCE_ATTRIBUTE_MAP[
|
||||
COLLECTION_NAME]['parent']
|
||||
controller = base.create_resource(
|
||||
COLLECTION_NAME,
|
||||
RESOURCE_NAME,
|
||||
plugin,
|
||||
params,
|
||||
parent=parent,
|
||||
allow_pagination=True,
|
||||
allow_sorting=True)
|
||||
exts = [
|
||||
extensions.ResourceExtension(
|
||||
COLLECTION_NAME,
|
||||
controller,
|
||||
parent,
|
||||
attr_map=params)
|
||||
]
|
||||
return exts
|
@ -66,7 +66,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
||||
# Version 1.6: Added "is_default" field
|
||||
# Version 1.7: Added floating IP bindings
|
||||
# Version 1.8: Added router gateway QoS policy bindings
|
||||
VERSION = '1.8'
|
||||
# Version 1.9: Added QosPacketRateLimitRule
|
||||
VERSION = '1.9'
|
||||
|
||||
# required by RbacNeutronMetaclass
|
||||
rbac_db_cls = QosPolicyRBAC
|
||||
@ -376,10 +377,22 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
||||
return set(bound_tenants)
|
||||
|
||||
def obj_make_compatible(self, primitive, target_version):
|
||||
def filter_rules(obj_names, rules):
|
||||
return [rule for rule in rules if
|
||||
rule['versioned_object.name'] in obj_names]
|
||||
_target_version = versionutils.convert_version_to_tuple(target_version)
|
||||
if _target_version < (1, 8):
|
||||
raise exception.IncompatibleObjectVersion(
|
||||
objver=target_version, objname=self.__class__.__name__)
|
||||
names = [
|
||||
rule_obj_impl.QosBandwidthLimitRule.obj_name(),
|
||||
rule_obj_impl.QosDscpMarkingRule.obj_name(),
|
||||
rule_obj_impl.QosMinimumBandwidthRule.obj_name(),
|
||||
]
|
||||
if _target_version >= (1, 9):
|
||||
names.append(rule_obj_impl.QosPacketRateLimitRule.obj_name())
|
||||
if 'rules' in primitive and names:
|
||||
primitive['rules'] = filter_rules(names, primitive['rules'])
|
||||
|
||||
|
||||
@base_db.NeutronObjectRegistry.register
|
||||
|
@ -26,6 +26,7 @@ from oslo_versionedobjects import fields as obj_fields
|
||||
|
||||
from neutron.db.qos import models as qos_db_model
|
||||
from neutron.objects import base
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
DSCP_MARK = 'dscp_mark'
|
||||
|
||||
@ -36,7 +37,7 @@ def get_rules(obj_cls, context, qos_policy_id):
|
||||
return all_rules
|
||||
|
||||
with obj_cls.db_context_reader(context):
|
||||
for rule_type in qos_consts.VALID_RULE_TYPES:
|
||||
for rule_type in qos_constants.VALID_RULE_TYPES:
|
||||
rule_cls_name = 'Qos%sRule' % helpers.camelize(rule_type)
|
||||
rule_cls = getattr(sys.modules[__name__], rule_cls_name)
|
||||
|
||||
@ -50,11 +51,12 @@ class QosRule(base.NeutronDbObject, metaclass=abc.ABCMeta):
|
||||
# 1.1: Added DscpMarkingRule
|
||||
# 1.2: Added QosMinimumBandwidthRule
|
||||
# 1.3: Added direction for BandwidthLimitRule
|
||||
# 1.4: Added PacketRateLimitRule
|
||||
#
|
||||
# NOTE(mangelajo): versions need to be handled from the top QosRule object
|
||||
# because it's the only reference QosPolicy can make
|
||||
# to them via obj_relationships version map
|
||||
VERSION = '1.3'
|
||||
VERSION = '1.4'
|
||||
|
||||
fields = {
|
||||
'id': common_types.UUIDField(),
|
||||
@ -167,3 +169,20 @@ class QosMinimumBandwidthRule(QosRule):
|
||||
duplicates_compare_fields = ['direction']
|
||||
|
||||
rule_type = qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH
|
||||
|
||||
|
||||
@base.NeutronObjectRegistry.register
|
||||
class QosPacketRateLimitRule(QosRule):
|
||||
|
||||
db_model = qos_db_model.QosPacketRateLimitRule
|
||||
|
||||
fields = {
|
||||
'max_kpps': obj_fields.IntegerField(nullable=True),
|
||||
'max_burst_kpps': obj_fields.IntegerField(nullable=True),
|
||||
'direction': common_types.FlowDirectionEnumField(
|
||||
default=constants.EGRESS_DIRECTION)
|
||||
}
|
||||
|
||||
duplicates_compare_fields = ['direction']
|
||||
|
||||
rule_type = qos_constants.RULE_TYPE_PACKET_RATE_LIMIT
|
||||
|
@ -13,17 +13,17 @@
|
||||
from neutron_lib.objects import common_types
|
||||
from neutron_lib.plugins import constants
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
from oslo_versionedobjects import fields as obj_fields
|
||||
|
||||
from neutron.objects import base
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
|
||||
class RuleTypeField(obj_fields.BaseEnumField):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.AUTO_TYPE = obj_fields.Enum(
|
||||
valid_values=qos_consts.VALID_RULE_TYPES)
|
||||
valid_values=qos_constants.VALID_RULE_TYPES)
|
||||
super(RuleTypeField, self).__init__(**kwargs)
|
||||
|
||||
|
||||
@ -33,7 +33,8 @@ class QosRuleType(base.NeutronObject):
|
||||
# Version 1.1: Added QosDscpMarkingRule
|
||||
# Version 1.2: Added QosMinimumBandwidthRule
|
||||
# Version 1.3: Added drivers field
|
||||
VERSION = '1.3'
|
||||
# Version 1.4: Added QosPacketRateLimitRule
|
||||
VERSION = '1.4'
|
||||
|
||||
fields = {
|
||||
'type': RuleTypeField(),
|
||||
|
22
neutron/services/qos/constants.py
Normal file
22
neutron/services/qos/constants.py
Normal file
@ -0,0 +1,22 @@
|
||||
#
|
||||
# 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_lib.services.qos import constants as qos_consts
|
||||
|
||||
# TODO(liuyulong): Because of the development sequence, the rule must
|
||||
# be implemented in Neutron first. Then the following can be moved
|
||||
# to neutron-lib after neutron has the new rule.
|
||||
# Add qos rule packet rate limit
|
||||
RULE_TYPE_PACKET_RATE_LIMIT = 'packet_rate_limit'
|
||||
VALID_RULE_TYPES = qos_consts.VALID_RULE_TYPES + [RULE_TYPE_PACKET_RATE_LIMIT]
|
@ -24,6 +24,7 @@ from neutron.api.rpc.callbacks.producer import registry as rpc_registry
|
||||
from neutron.api.rpc.callbacks import resources
|
||||
from neutron.api.rpc.handlers import resources_rpc
|
||||
from neutron.objects.qos import policy as policy_object
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -168,7 +169,7 @@ class QosServiceDriverManager(object):
|
||||
if not self._drivers:
|
||||
return []
|
||||
|
||||
rule_types = set(qos_consts.VALID_RULE_TYPES)
|
||||
rule_types = set(qos_constants.VALID_RULE_TYPES)
|
||||
|
||||
# Recalculate on every call to allow drivers determine supported rule
|
||||
# types dynamically
|
||||
|
@ -22,6 +22,7 @@ from neutron_lib.api.definitions import qos_bw_limit_direction
|
||||
from neutron_lib.api.definitions import qos_bw_minimum_ingress
|
||||
from neutron_lib.api.definitions import qos_default
|
||||
from neutron_lib.api.definitions import qos_port_network_policy
|
||||
from neutron_lib.api.definitions import qos_pps_rule
|
||||
from neutron_lib.api.definitions import qos_rule_type_details
|
||||
from neutron_lib.api.definitions import qos_rules_alias
|
||||
from neutron_lib.callbacks import events as callbacks_events
|
||||
@ -64,14 +65,17 @@ class QoSPlugin(qos.QoSPluginBase):
|
||||
service parameters over ports and networks.
|
||||
|
||||
"""
|
||||
supported_extension_aliases = [qos_apidef.ALIAS,
|
||||
qos_bw_limit_direction.ALIAS,
|
||||
qos_default.ALIAS,
|
||||
qos_rule_type_details.ALIAS,
|
||||
port_resource_request.ALIAS,
|
||||
qos_bw_minimum_ingress.ALIAS,
|
||||
qos_rules_alias.ALIAS,
|
||||
qos_port_network_policy.ALIAS]
|
||||
supported_extension_aliases = [
|
||||
qos_apidef.ALIAS,
|
||||
qos_bw_limit_direction.ALIAS,
|
||||
qos_default.ALIAS,
|
||||
qos_rule_type_details.ALIAS,
|
||||
port_resource_request.ALIAS,
|
||||
qos_bw_minimum_ingress.ALIAS,
|
||||
qos_rules_alias.ALIAS,
|
||||
qos_port_network_policy.ALIAS,
|
||||
qos_pps_rule.ALIAS,
|
||||
]
|
||||
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
@ -13,6 +13,7 @@
|
||||
import random
|
||||
from unittest import mock
|
||||
|
||||
from neutron_lib import constants as lib_consts
|
||||
from neutron_lib.exceptions import qos as qos_exc
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
from oslo_utils import uuidutils
|
||||
@ -24,6 +25,7 @@ from neutron.objects import ports as port_obj
|
||||
from neutron.objects.qos import binding
|
||||
from neutron.objects.qos import policy
|
||||
from neutron.objects.qos import rule
|
||||
from neutron.services.qos import constants as q_consts
|
||||
from neutron.tests.unit.objects import test_base
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
@ -32,6 +34,7 @@ RULE_OBJ_CLS = {
|
||||
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: rule.QosBandwidthLimitRule,
|
||||
qos_consts.RULE_TYPE_DSCP_MARKING: rule.QosDscpMarkingRule,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: rule.QosMinimumBandwidthRule,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT: rule.QosPacketRateLimitRule,
|
||||
}
|
||||
|
||||
|
||||
@ -173,7 +176,10 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
for rule_type in rule_type):
|
||||
rule_fields = self.get_random_object_fields(obj_cls=obj_cls)
|
||||
rule_fields['qos_policy_id'] = policy_obj.id
|
||||
if (obj_cls.rule_type == qos_consts.RULE_TYPE_BANDWIDTH_LIMIT and
|
||||
if (obj_cls.rule_type in [
|
||||
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT] and
|
||||
bwlimit_direction is not None):
|
||||
rule_fields['direction'] = bwlimit_direction
|
||||
rule_obj = obj_cls(self.context, **rule_fields)
|
||||
@ -184,6 +190,11 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
policy_obj.obj_load_attr('rules')
|
||||
return policy_obj, rules
|
||||
|
||||
@staticmethod
|
||||
def _policy_through_version(obj, version):
|
||||
primitive = obj.obj_to_primitive(target_version=version)
|
||||
return policy.QosPolicy.clean_obj_from_primitive(primitive)
|
||||
|
||||
def test_attach_network_get_network_policy(self):
|
||||
|
||||
obj = self._create_test_policy()
|
||||
@ -456,6 +467,20 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
self.assertRaises(exception.IncompatibleObjectVersion,
|
||||
policy_obj.obj_to_primitive, '1.7')
|
||||
|
||||
def test_object_version_degradation_less_than_1_9(self):
|
||||
policy_obj, rule_objs = self._create_test_policy_with_rules(
|
||||
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_DSCP_MARKING,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT], reload_rules=True,
|
||||
bwlimit_direction=lib_consts.INGRESS_DIRECTION)
|
||||
policy_obj_v1_8 = self._policy_through_version(policy_obj, '1.8')
|
||||
|
||||
self.assertIn(rule_objs[0], policy_obj_v1_8.rules)
|
||||
self.assertIn(rule_objs[1], policy_obj_v1_8.rules)
|
||||
self.assertIn(rule_objs[2], policy_obj_v1_8.rules)
|
||||
self.assertNotIn(rule_objs[3], policy_obj_v1_8.rules)
|
||||
|
||||
@mock.patch.object(policy.QosPolicy, 'unset_default')
|
||||
def test_filter_by_shared(self, *mocks):
|
||||
project_id = uuidutils.generate_uuid()
|
||||
|
@ -18,6 +18,7 @@ from oslo_versionedobjects import exception
|
||||
|
||||
from neutron.objects.qos import policy
|
||||
from neutron.objects.qos import rule
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.tests import base as neutron_test_base
|
||||
from neutron.tests.unit.objects import test_base
|
||||
from neutron.tests.unit import testlib_api
|
||||
@ -241,3 +242,51 @@ class QosMinimumBandwidthRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
id=generated_qos_policy_id,
|
||||
project_id=uuidutils.generate_uuid())
|
||||
policy_obj.create()
|
||||
|
||||
|
||||
class QosPacketRateLimitRuleObjectTestCase(test_base.BaseObjectIfaceTestCase):
|
||||
|
||||
_test_class = rule.QosPacketRateLimitRule
|
||||
|
||||
def test_to_dict_returns_type(self):
|
||||
obj = rule.QosPacketRateLimitRule(self.context, **self.db_objs[0])
|
||||
dict_ = obj.to_dict()
|
||||
self.assertEqual(qos_constants.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
dict_['type'])
|
||||
|
||||
def test_duplicate_rules(self):
|
||||
policy_id = uuidutils.generate_uuid()
|
||||
ingress_rule_1 = rule.QosPacketRateLimitRule(
|
||||
self.context, qos_policy_id=policy_id,
|
||||
max_kpps=2000, max_burst=800,
|
||||
direction=constants.INGRESS_DIRECTION)
|
||||
ingress_rule_2 = rule.QosPacketRateLimitRule(
|
||||
self.context, qos_policy_id=policy_id,
|
||||
max_kpps=3000, max_burst=200,
|
||||
direction=constants.INGRESS_DIRECTION)
|
||||
egress_rule = rule.QosPacketRateLimitRule(
|
||||
self.context, qos_policy_id=policy_id,
|
||||
max_kpps=1000, max_burst=500,
|
||||
direction=constants.EGRESS_DIRECTION)
|
||||
dscp_rule = rule.QosDscpMarkingRule(
|
||||
self.context, qos_policy_id=policy_id, dscp_mark=16)
|
||||
self.assertTrue(ingress_rule_1.duplicates(ingress_rule_2))
|
||||
self.assertFalse(ingress_rule_1.duplicates(egress_rule))
|
||||
self.assertFalse(ingress_rule_1.duplicates(dscp_rule))
|
||||
|
||||
|
||||
class QosPacketRateLimitRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
testlib_api.SqlTestCase):
|
||||
|
||||
_test_class = rule.QosPacketRateLimitRule
|
||||
|
||||
def setUp(self):
|
||||
super(QosPacketRateLimitRuleDbObjectTestCase, self).setUp()
|
||||
|
||||
# Prepare policy to be able to insert a rule
|
||||
for obj in self.db_objs:
|
||||
generated_qos_policy_id = obj['qos_policy_id']
|
||||
policy_obj = policy.QosPolicy(self.context,
|
||||
id=generated_qos_policy_id,
|
||||
project_id=uuidutils.generate_uuid())
|
||||
policy_obj.create()
|
||||
|
@ -22,6 +22,7 @@ from oslo_config import cfg
|
||||
|
||||
from neutron import manager
|
||||
from neutron.objects.qos import rule_type
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.services.qos import qos_plugin
|
||||
from neutron.tests import base as test_base
|
||||
|
||||
@ -78,11 +79,11 @@ class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
|
||||
|
||||
def test_get_objects(self):
|
||||
rule_types_mock = mock.PropertyMock(
|
||||
return_value=set(qos_consts.VALID_RULE_TYPES))
|
||||
return_value=set(qos_constants.VALID_RULE_TYPES))
|
||||
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
|
||||
new_callable=rule_types_mock):
|
||||
types = rule_type.QosRuleType.get_objects()
|
||||
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
|
||||
self.assertEqual(sorted(qos_constants.VALID_RULE_TYPES),
|
||||
sorted(type_['type'] for type_ in types))
|
||||
|
||||
def test_wrong_type(self):
|
||||
|
@ -82,13 +82,14 @@ object_data = {
|
||||
'PortUplinkStatusPropagation': '1.1-f0a4ca451a941910376c33616dea5de2',
|
||||
'ProviderResourceAssociation': '1.0-05ab2d5a3017e5ce9dd381328f285f34',
|
||||
'ProvisioningBlock': '1.0-c19d6d05bfa8143533471c1296066125',
|
||||
'QosBandwidthLimitRule': '1.3-51b662b12a8d1dfa89288d826c6d26d3',
|
||||
'QosDscpMarkingRule': '1.3-0313c6554b34fd10c753cb63d638256c',
|
||||
'QosMinimumBandwidthRule': '1.3-314c3419f4799067cc31cc319080adff',
|
||||
'QosBandwidthLimitRule': '1.4-51b662b12a8d1dfa89288d826c6d26d3',
|
||||
'QosDscpMarkingRule': '1.4-0313c6554b34fd10c753cb63d638256c',
|
||||
'QosMinimumBandwidthRule': '1.4-314c3419f4799067cc31cc319080adff',
|
||||
'QosPacketRateLimitRule': '1.4-18411fa95f54602b8c8a5da2d3194b31',
|
||||
'QosPolicyRBAC': '1.1-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'QosRuleType': '1.3-7286188edeb3a0386f9cf7979b9700fc',
|
||||
'QosRuleType': '1.4-a5b870dfa6f510a91f5cb0216873064e',
|
||||
'QosRuleTypeDriver': '1.0-7d8cb9f0ef661ac03700eae97118e3db',
|
||||
'QosPolicy': '1.8-4adb0cde3102c10d8970ec9487fd7fe7',
|
||||
'QosPolicy': '1.9-4adb0cde3102c10d8970ec9487fd7fe7',
|
||||
'QosPolicyDefault': '1.0-59e5060eedb1f06dd0935a244d27d11c',
|
||||
'QosPolicyFloatingIPBinding': '1.0-5625df4205a18778cd6aa40f99be024e',
|
||||
'QosPolicyRouterGatewayIPBinding': '1.0-da064fbfe5ee18c950b905b483bf59e3',
|
||||
|
@ -38,6 +38,7 @@ from neutron.objects import network as network_object
|
||||
from neutron.objects import ports as ports_object
|
||||
from neutron.objects.qos import policy as policy_object
|
||||
from neutron.objects.qos import rule as rule_object
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.services.qos import qos_plugin
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||
from neutron.tests.unit.services.qos import base
|
||||
@ -98,7 +99,11 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
'dscp_mark': 16},
|
||||
'minimum_bandwidth_rule': {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'min_kbps': 10}}
|
||||
'min_kbps': 10},
|
||||
'packet_rate_limit_rule': {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'max_kpps': 20,
|
||||
'max_burst_kpps': 130}}
|
||||
|
||||
self.policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
@ -112,6 +117,9 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
self.min_rule = rule_object.QosMinimumBandwidthRule(
|
||||
self.ctxt, **self.rule_data['minimum_bandwidth_rule'])
|
||||
|
||||
self.pps_rule = rule_object.QosPacketRateLimitRule(
|
||||
self.ctxt, **self.rule_data['packet_rate_limit_rule'])
|
||||
|
||||
def _validate_driver_params(self, method_name, ctxt):
|
||||
call_args = self.qos_plugin.driver_manager.call.call_args[0]
|
||||
self.assertTrue(self.qos_plugin.driver_manager.call.called)
|
||||
@ -1025,12 +1033,12 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
|
||||
def test_get_rule_types(self):
|
||||
rule_types_mock = mock.PropertyMock(
|
||||
return_value=qos_consts.VALID_RULE_TYPES)
|
||||
return_value=qos_constants.VALID_RULE_TYPES)
|
||||
filters = {'type': 'type_id'}
|
||||
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
|
||||
new_callable=rule_types_mock):
|
||||
types = self.qos_plugin.get_rule_types(self.ctxt, filters=filters)
|
||||
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
|
||||
self.assertEqual(sorted(qos_constants.VALID_RULE_TYPES),
|
||||
sorted(type_['type'] for type_ in types))
|
||||
|
||||
@mock.patch('neutron.objects.ports.Port')
|
||||
@ -1078,6 +1086,180 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
self.assertLess(
|
||||
action_index, mock_manager.mock_calls.index(driver_mock_call))
|
||||
|
||||
def test_create_policy_packet_rate_limit_rule(self):
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=_policy):
|
||||
setattr(_policy, "rules", [self.pps_rule])
|
||||
self.qos_plugin.create_policy_packet_rate_limit_rule(
|
||||
self.ctxt, self.policy.id, self.rule_data)
|
||||
self._validate_driver_params('update_policy', self.ctxt)
|
||||
|
||||
def test_create_policy_pps_rule_duplicates(self):
|
||||
_policy = self._get_policy()
|
||||
setattr(_policy, "rules", [self.pps_rule])
|
||||
new_rule_data = {
|
||||
'packet_rate_limit_rule': {
|
||||
'max_kpps': 400,
|
||||
'direction': self.pps_rule.direction
|
||||
}
|
||||
}
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=_policy) as mock_qos_get_obj:
|
||||
self.assertRaises(
|
||||
qos_exc.QoSRulesConflict,
|
||||
self.qos_plugin.create_policy_packet_rate_limit_rule,
|
||||
self.ctxt, _policy.id, new_rule_data)
|
||||
mock_qos_get_obj.assert_called_once_with(self.ctxt, id=_policy.id)
|
||||
|
||||
def test_update_policy_packet_rate_limit_rule(self):
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=_policy):
|
||||
setattr(_policy, "rules", [self.pps_rule])
|
||||
self.qos_plugin.update_policy_packet_rate_limit_rule(
|
||||
self.ctxt, self.pps_rule.id, self.policy.id, self.rule_data)
|
||||
self._validate_driver_params('update_policy', self.ctxt)
|
||||
|
||||
def test_update_policy_pps_rule_bad_policy(self):
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=_policy):
|
||||
setattr(_policy, "rules", [])
|
||||
self.assertRaises(
|
||||
qos_exc.QosRuleNotFound,
|
||||
self.qos_plugin.update_policy_packet_rate_limit_rule,
|
||||
self.ctxt, self.pps_rule.id, self.policy.id,
|
||||
self.rule_data)
|
||||
|
||||
def test_delete_policy_packet_rate_limit_rule(self):
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=_policy):
|
||||
setattr(_policy, "rules", [self.pps_rule])
|
||||
self.qos_plugin.delete_policy_packet_rate_limit_rule(
|
||||
self.ctxt, self.pps_rule.id, self.policy.id)
|
||||
self._validate_driver_params('update_policy', self.ctxt)
|
||||
|
||||
def test_delete_policy_pps_rule_bad_policy(self):
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=_policy):
|
||||
setattr(_policy, "rules", [])
|
||||
self.assertRaises(
|
||||
qos_exc.QosRuleNotFound,
|
||||
self.qos_plugin.delete_policy_packet_rate_limit_rule,
|
||||
self.ctxt, self.pps_rule.id, _policy.id)
|
||||
|
||||
def test_get_policy_packet_rate_limit_rule(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=self.policy):
|
||||
with mock.patch('neutron.objects.qos.rule.'
|
||||
'QosPacketRateLimitRule.'
|
||||
'get_object') as get_object_mock:
|
||||
self.qos_plugin.get_policy_packet_rate_limit_rule(
|
||||
self.ctxt, self.pps_rule.id, self.policy.id)
|
||||
get_object_mock.assert_called_once_with(self.ctxt,
|
||||
id=self.pps_rule.id)
|
||||
|
||||
def test_get_policy_packet_rate_limit_rules_for_policy(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=self.policy):
|
||||
with mock.patch('neutron.objects.qos.rule.'
|
||||
'QosPacketRateLimitRule.'
|
||||
'get_objects') as get_objects_mock:
|
||||
self.qos_plugin.get_policy_packet_rate_limit_rules(
|
||||
self.ctxt, self.policy.id)
|
||||
get_objects_mock.assert_called_once_with(
|
||||
self.ctxt, _pager=mock.ANY, qos_policy_id=self.policy.id)
|
||||
|
||||
def test_get_policy_packet_rate_limit_rules_for_policy_with_filters(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=self.policy):
|
||||
with mock.patch('neutron.objects.qos.rule.'
|
||||
'QosPacketRateLimitRule.'
|
||||
'get_objects') as get_objects_mock:
|
||||
filters = {'filter': 'filter_id'}
|
||||
self.qos_plugin.get_policy_packet_rate_limit_rules(
|
||||
self.ctxt, self.policy.id, filters=filters)
|
||||
get_objects_mock.assert_called_once_with(
|
||||
self.ctxt, _pager=mock.ANY,
|
||||
qos_policy_id=self.policy.id,
|
||||
filter='filter_id')
|
||||
|
||||
def test_get_policy_packet_rate_limit_rule_for_nonexistent_policy(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
qos_exc.QosPolicyNotFound,
|
||||
self.qos_plugin.get_policy_packet_rate_limit_rule,
|
||||
self.ctxt, self.pps_rule.id, self.policy.id)
|
||||
|
||||
def test_get_policy_packet_rate_limit_rules_for_nonexistent_policy(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
qos_exc.QosPolicyNotFound,
|
||||
self.qos_plugin.get_policy_packet_rate_limit_rules,
|
||||
self.ctxt, self.policy.id)
|
||||
|
||||
def test_create_policy_pps_rule_for_nonexistent_policy(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
qos_exc.QosPolicyNotFound,
|
||||
self.qos_plugin.create_policy_packet_rate_limit_rule,
|
||||
self.ctxt, self.policy.id, self.rule_data)
|
||||
|
||||
def test_update_policy_pps_rule_for_nonexistent_policy(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
qos_exc.QosPolicyNotFound,
|
||||
self.qos_plugin.update_policy_packet_rate_limit_rule,
|
||||
self.ctxt, self.pps_rule.id, self.policy.id, self.rule_data)
|
||||
|
||||
def test_delete_policy_pps_rule_for_nonexistent_policy(self):
|
||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
qos_exc.QosPolicyNotFound,
|
||||
self.qos_plugin.delete_policy_packet_rate_limit_rule,
|
||||
self.ctxt, self.pps_rule.id, self.policy.id)
|
||||
|
||||
def test_get_pps_rule_type(self):
|
||||
admin_ctxt = context.get_admin_context()
|
||||
drivers_details = [{
|
||||
'name': 'fake-driver',
|
||||
'supported_parameters': [{
|
||||
'parameter_name': 'max_kpps',
|
||||
'parameter_type': lib_constants.VALUES_TYPE_RANGE,
|
||||
'parameter_range': {'start': 0, 'end': 100}
|
||||
}]
|
||||
}]
|
||||
with mock.patch.object(
|
||||
qos_plugin.QoSPlugin, "supported_rule_type_details",
|
||||
return_value=drivers_details
|
||||
):
|
||||
rule_type_details = self.qos_plugin.get_rule_type(
|
||||
admin_ctxt, qos_constants.RULE_TYPE_PACKET_RATE_LIMIT)
|
||||
self.assertEqual(
|
||||
qos_constants.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
rule_type_details['type'])
|
||||
self.assertEqual(
|
||||
drivers_details, rule_type_details['drivers'])
|
||||
|
||||
def test_get_pps_rule_type_as_user(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotAuthorized,
|
||||
self.qos_plugin.get_rule_type,
|
||||
self.ctxt, qos_constants.RULE_TYPE_PACKET_RATE_LIMIT)
|
||||
|
||||
|
||||
class QoSRuleAliasTestExtensionManager(object):
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added new API extension to QoS service plugin
|
||||
to support CRUD actions for packet rate limit (packet per
|
||||
second) rule in Neutron server side.
|
@ -234,6 +234,7 @@ neutron.objects =
|
||||
QosBandwidthLimitRule = neutron.objects.qos.rule:QosBandwidthLimitRule
|
||||
QosDscpMarkingRule = neutron.objects.qos.rule:QosDscpMarkingRule
|
||||
QosMinimumBandwidthRule = neutron.objects.qos.rule:QosMinimumBandwidthRule
|
||||
QosPacketRateLimitRule = neutron.objects.qos.rule:QosPacketRateLimitRule
|
||||
QosPolicy = neutron.objects.qos.policy:QosPolicy
|
||||
QosPolicyDefault = neutron.objects.qos.policy:QosPolicyDefault
|
||||
QosPolicyFloatingIPBinding = neutron.objects.qos.binding:QosPolicyFloatingIPBinding
|
||||
|
Loading…
Reference in New Issue
Block a user