Merge "[QoS] Add rule type packet per second (pps)"
This commit is contained in:
commit
86de15d632
@ -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.
|
@ -235,6 +235,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