Add API extension for QoS minimum pps rule

This patch implements support for CRUD operations for QoS minimum
packet rate, for example:

DELETE /qos/policies/$POLICY_ID/minimum_packet_rate_rules/$RULE_ID

Placement or dataplane enforcement is not implemented yet.

Partial-Bug: #1922237
See-Also: https://review.opendev.org/785236
Change-Id: Ie994bdab62bab33737f25287e568519c782dea9a
This commit is contained in:
Przemyslaw Szczerbik 2021-07-12 09:02:02 +02:00
parent 1d450dbddc
commit 56044db26d
24 changed files with 906 additions and 57 deletions

View File

@ -38,24 +38,28 @@ QoS supported rule types are now available as ``VALID_RULE_TYPES`` in `QoS rule
* minimum_bandwidth: Minimum bandwidth constraints on certain types of traffic.
* minimum_packet_rate: Minimum packet rate constraints on certain types of traffic.
Any QoS driver can claim support for some QoS rule types
by providing a driver property called
``supported_rules``, the QoS driver manager will recalculate rule types
dynamically that the QoS driver supports.
dynamically that the QoS driver supports. In the most simple case, the
property can be represented by a simple Python list defined on the class.
The following table shows the Networking back ends, QoS supported rules, and
traffic directions (from the VM point of view).
.. table:: **Networking back ends, supported rules, and traffic direction**
==================== ======================= ======================= =================== ===================
Rule \\ back end Open vSwitch SR-IOV Linux bridge OVN
==================== ======================= ======================= =================== ===================
Bandwidth limit Egress \\ Ingress Egress (1) Egress \\ Ingress Egress \\ Ingress
Minimum bandwidth Egress \\ Ingress (2) Egress \\ Ingress (2) - -
DSCP marking Egress - Egress Egress
==================== ======================= ======================= =================== ===================
==================== ============================= ======================= =================== ===================
Rule \\ back end Open vSwitch SR-IOV Linux bridge OVN
==================== ============================= ======================= =================== ===================
Bandwidth limit Egress \\ Ingress Egress (1) Egress \\ Ingress Egress \\ Ingress
Minimum bandwidth Egress \\ Ingress (2) Egress \\ Ingress (2) - -
Minimum packet rate - - - -
DSCP marking Egress - Egress Egress
==================== ============================= ======================= =================== ===================
.. note::
@ -78,8 +82,14 @@ traffic directions (from the VM point of view).
(1) Since Newton
(2) Since Stein
In the most simple case, the property can be represented by a simple Python
list defined on the class.
.. table:: **Neutron backends, supported directions and enforcement types for Minimum Packet Rate rule**
============================ ==================== ==================== ============== =====
Enforcement type \ Backend Open vSwitch SR-IOV Linux Bridge OVN
============================ ==================== ==================== ============== =====
Dataplane - - - -
Placement - - - -
============================ ==================== ==================== ============== =====
For an ml2 plug-in, the list of supported QoS rule types and parameters is
defined as a common subset of rules supported by all active mechanism drivers.
@ -328,6 +338,15 @@ To enable minimum bandwidth rule:
"delete_policy_minimum_bandwidth_rule": "rule:regular_user",
"update_policy_minimum_bandwidth_rule": "rule:regular_user",
To enable minimum packet rate rule:
.. code-block:: none
"get_policy_minimum_packet_rate_rule": "rule:regular_user",
"create_policy_minimum_packet_rate_rule": "rule:regular_user",
"delete_policy_minimum_packet_rate_rule": "rule:regular_user",
"update_policy_minimum_packet_rate_rule": "rule:regular_user",
User workflow
~~~~~~~~~~~~~

View File

@ -151,6 +151,8 @@ From database point of view, following objects are defined in schema:
bits for egress traffic.
* QosMinimumBandwidthRule: defines the rule that creates a minimum bandwidth
constraint.
* QosMinimumPacketRateRule: defines the rule that creates a minimum packet rate
constraint.
All database models are defined under:
@ -176,6 +178,9 @@ For QoS, the following neutron objects are implemented:
characterized by a min_kbps parameter. This rule has also a direction
parameter to set the traffic direction, from the instance point of view. The
only direction now implemented is egress.
* QosMinimumPacketRateRule: defines the minimum assured packet rate rule type,
characterized by a min_kpps parameter. This rule has also a direction
parameter to set the traffic direction, from the instance point of view.
Those are defined in:

View File

@ -79,6 +79,13 @@ def build_resource_info(plural_mappings, resource_map, which_service,
for collection_name in resource_map:
resource_name = plural_mappings[collection_name]
params = resource_map.get(collection_name, {})
# If SUB_RESOURCE_ATTRIBUTE_MAP was passed in as a resource_map, we
# need special handling for it. SUB_RESOURCE_ATTRIBUTE_MAP must have
# a 'parent' and 'parameters' keys. 'parameters' key is going to
# contain sub-resources that are being extended.
parent = params.get('parent')
params = params['parameters'] if params.get('parameters') else params
if translate_name:
collection_name = collection_name.replace('_', '-')
if register_quota:
@ -89,12 +96,14 @@ def build_resource_info(plural_mappings, resource_map, which_service,
member_actions=member_actions,
allow_bulk=allow_bulk,
allow_pagination=True,
allow_sorting=True)
allow_sorting=True,
parent=parent)
resource = extensions.ResourceExtension(
collection_name,
controller,
path_prefix=path_prefix,
member_actions=member_actions,
attr_map=params)
attr_map=params,
parent=parent)
resources.append(resource)
return resources

View File

@ -343,6 +343,61 @@ rules = [
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY)
),
policy.DocumentedRuleDefault(
name='get_policy_minimum_packet_rate_rule',
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Get a QoS minimum packet rate rule',
operations=[
{
'method': 'GET',
'path': '/qos/policies/{policy_id}/minimum_packet_rate_rules',
},
{
'method': 'GET',
'path': ('/qos/policies/{policy_id}/'
'minimum_packet_rate_rules/{rule_id}'),
},
],
),
policy.DocumentedRuleDefault(
name='create_policy_minimum_packet_rate_rule',
check_str=base.SYSTEM_ADMIN,
scope_types=['system'],
description='Create a QoS minimum packet rate rule',
operations=[
{
'method': 'POST',
'path': '/qos/policies/{policy_id}/minimum_packet_rate_rules',
},
],
),
policy.DocumentedRuleDefault(
name='update_policy_minimum_packet_rate_rule',
check_str=base.SYSTEM_ADMIN,
scope_types=['system'],
description='Update a QoS minimum packet rate rule',
operations=[
{
'method': 'PUT',
'path': ('/qos/policies/{policy_id}/'
'minimum_packet_rate_rules/{rule_id}'),
},
],
),
policy.DocumentedRuleDefault(
name='delete_policy_minimum_packet_rate_rule',
check_str=base.SYSTEM_ADMIN,
scope_types=['system'],
description='Delete a QoS minimum packet rate rule',
operations=[
{
'method': 'DELETE',
'path': ('/qos/policies/{policy_id}/'
'minimum_packet_rate_rules/{rule_id}'),
},
],
),
policy.DocumentedRuleDefault(
name='get_alias_bandwidth_limit_rule',
check_str='rule:get_policy_bandwidth_limit_rule',

View File

@ -1 +1 @@
1bb3393de75d
c181bb1d89e4

View File

@ -0,0 +1,56 @@
# Copyright (c) 2021 Ericsson Software Technology
#
# 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 alembic import op
from neutron_lib import constants as n_const
from neutron_lib.db import constants as db_const
import sqlalchemy as sa
from neutron.db import migration
"""qos_minimum_packet_rate_rules
Revision ID: c181bb1d89e4
Revises: 1bb3393de75d
Create Date: 2021-07-09 15:47:46.826903
"""
# revision identifiers, used by Alembic.
revision = 'c181bb1d89e4'
down_revision = '1bb3393de75d'
# milestone identifier, used by neutron-db-manage
neutron_milestone = [migration.YOGA]
def upgrade():
op.create_table(
'qos_minimum_packet_rate_rules',
sa.Column('id', sa.String(db_const.UUID_FIELD_SIZE),
primary_key=True),
sa.Column('qos_policy_id', sa.String(db_const.UUID_FIELD_SIZE),
sa.ForeignKey('qos_policies.id', ondelete='CASCADE'),
index=True),
sa.Column('min_kpps', sa.Integer(), nullable=False),
sa.Column('direction',
sa.Enum(*n_const.VALID_DIRECTIONS_AND_ANY,
name="qos_minimum_packet_rate_rules_directions"),
nullable=False,
server_default=n_const.EGRESS_DIRECTION),
sa.UniqueConstraint('qos_policy_id', 'direction',
name='qos_minimum_packet_rate_rules0qos_policy_id0direction')
)

View File

@ -218,3 +218,27 @@ class QosPacketRateLimitRule(model_base.HasId, model_base.BASEV2):
name="qos_packet_rate_limit_rules0qos_policy_id0direction"),
model_base.BASEV2.__table_args__
)
class QosMinimumPacketRateRule(model_base.HasId, model_base.BASEV2):
__tablename__ = 'qos_minimum_packet_rate_rules'
qos_policy_id = sa.Column(sa.String(db_const.UUID_FIELD_SIZE),
sa.ForeignKey('qos_policies.id',
ondelete='CASCADE'),
index=True)
min_kpps = sa.Column(sa.Integer(), nullable=False)
direction = sa.Column(
sa.Enum(*constants.VALID_DIRECTIONS_AND_ANY,
name='qos_minimum_packet_rate_rules_directions'),
nullable=False,
default=constants.EGRESS_DIRECTION,
server_default=constants.EGRESS_DIRECTION)
revises_on_change = ('qos_policy', )
qos_policy = sa.orm.relationship(QosPolicy, load_on_pending=True)
__table_args__ = (
sa.UniqueConstraint(
qos_policy_id, direction,
name='qos_minimum_packet_rate_rules0qos_policy_id0direction'),
model_base.BASEV2.__table_args__
)

View File

@ -88,6 +88,7 @@ class QoSPluginBase(service_base.ServicePluginBase, metaclass=abc.ABCMeta):
'bandwidth_limit': rule_object.QosBandwidthLimitRule,
'dscp_marking': rule_object.QosDscpMarkingRule,
'minimum_bandwidth': rule_object.QosMinimumBandwidthRule,
'minimum_packet_rate': rule_object.QosMinimumPacketRateRule,
'packet_rate_limit': rule_object.QosPacketRateLimitRule,
}

View File

@ -0,0 +1,35 @@
# Copyright (c) 2021 Ericsson Software Technology
#
# 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_pps_minimum_rule as apidef
from neutron_lib.api import extensions as api_extensions
from neutron_lib.plugins import constants as nl_pl_const
from neutron.api.v2 import resource_helper
class Qos_pps_minimum_rule(api_extensions.APIExtensionDescriptor):
api_definition = apidef
@classmethod
def get_resources(cls):
plural_mappings = resource_helper.build_plural_mappings(
{}, apidef.SUB_RESOURCE_ATTRIBUTE_MAP)
return resource_helper.build_resource_info(
plural_mappings,
apidef.SUB_RESOURCE_ATTRIBUTE_MAP,
nl_pl_const.QOS,
translate_name=True,
allow_bulk=True)

View File

@ -67,7 +67,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
# Version 1.7: Added floating IP bindings
# Version 1.8: Added router gateway QoS policy bindings
# Version 1.9: Added QosPacketRateLimitRule
VERSION = '1.9'
# Version 1.10: Added QosMinimumPacketRateRule
VERSION = '1.10'
# required by RbacNeutronMetaclass
rbac_db_cls = QosPolicyRBAC
@ -391,6 +392,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
]
if _target_version >= (1, 9):
names.append(rule_obj_impl.QosPacketRateLimitRule.obj_name())
if _target_version >= (1, 10):
names.append(rule_obj_impl.QosMinimumPacketRuleRule.obj_name())
if 'rules' in primitive and names:
primitive['rules'] = filter_rules(names, primitive['rules'])

View File

@ -13,9 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron_lib import constants as n_consts
from neutron_lib.exceptions import qos as qos_exc
from neutron_lib.services.qos import constants as qos_consts
from neutron.services.qos import constants as qos_constants
def check_bandwidth_rule_conflict(policy, rule_data):
"""Implementation of the QoS Rule checker.
@ -65,3 +68,33 @@ def check_rules_conflict(policy, rule_obj):
new_rule_type=rule_obj.rule_type,
rule_id=rule.id,
policy_id=policy.id)
def check_min_pps_rule_conflict(policy, rule_obj):
"""Implementation of the QoS Rule checker.
This function checks if the new QoS minimum packet rate rule to be
associated with the policy doesn't conflict with the existing rules.
Raises an exception if conflict is identified.
"""
if (getattr(rule_obj, "rule_type", None) !=
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
return
for rule in policy.rules:
if rule.rule_type == qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE:
# Just like in check_rules_conflict(), we need to avoid raising
# exception when compared rules have got same ID.
if rule.id == getattr(rule_obj, "id", None):
continue
# Check if we are mixing directionless and direction-oriented QoS
# minimum packet rate rules
if getattr(rule_obj, "direction", None) and (
(rule_obj.direction == n_consts.ANY_DIRECTION and
rule.direction in n_consts.VALID_DIRECTIONS) or
(rule_obj.direction in n_consts.VALID_DIRECTIONS and
rule.direction == n_consts.ANY_DIRECTION)):
raise qos_exc.QoSRuleParameterConflict(
rule_value=rule_obj.direction,
policy_id=policy["id"],
existing_rule=rule.rule_type,
existing_value=rule.direction)

View File

@ -52,11 +52,12 @@ class QosRule(base.NeutronDbObject, metaclass=abc.ABCMeta):
# 1.2: Added QosMinimumBandwidthRule
# 1.3: Added direction for BandwidthLimitRule
# 1.4: Added PacketRateLimitRule
# 1.5: Added QosMinimumPacketRateRule
#
# 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.4'
VERSION = '1.5'
fields = {
'id': common_types.UUIDField(),
@ -186,3 +187,18 @@ class QosPacketRateLimitRule(QosRule):
duplicates_compare_fields = ['direction']
rule_type = qos_constants.RULE_TYPE_PACKET_RATE_LIMIT
@base.NeutronObjectRegistry.register
class QosMinimumPacketRateRule(QosRule):
db_model = qos_db_model.QosMinimumPacketRateRule
fields = {
'min_kpps': obj_fields.IntegerField(nullable=False),
'direction': common_types.FlowDirectionAndAnyEnumField(),
}
duplicates_compare_fields = ['direction']
rule_type = qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE

View File

@ -34,7 +34,8 @@ class QosRuleType(base.NeutronObject):
# Version 1.2: Added QosMinimumBandwidthRule
# Version 1.3: Added drivers field
# Version 1.4: Added QosPacketRateLimitRule
VERSION = '1.4'
# Version 1.5: Added QosMinimumPacketRateRule
VERSION = '1.5'
fields = {
'type': RuleTypeField(),

View File

@ -19,6 +19,7 @@ from neutron_lib.services.qos import constants as qos_consts
# to neutron-lib after neutron has the new rule.
# Add qos rule packet rate limit
RULE_TYPE_PACKET_RATE_LIMIT = 'packet_rate_limit'
RULE_TYPE_MINIMUM_PACKET_RATE = 'minimum_packet_rate'
# NOTE(przszc): Ensure that there are no duplicates in the list. Order of the
# items in the list must be stable, as QosRuleType OVO hash value depends on
# it.
@ -26,5 +27,7 @@ RULE_TYPE_PACKET_RATE_LIMIT = 'packet_rate_limit'
# from the list below.
VALID_RULE_TYPES = (qos_consts.VALID_RULE_TYPES +
([RULE_TYPE_PACKET_RATE_LIMIT] if RULE_TYPE_PACKET_RATE_LIMIT not in
qos_consts.VALID_RULE_TYPES else []) +
([RULE_TYPE_MINIMUM_PACKET_RATE] if RULE_TYPE_MINIMUM_PACKET_RATE not in
qos_consts.VALID_RULE_TYPES else [])
)

View File

@ -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_minimum_rule
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
@ -51,6 +52,7 @@ from neutron.objects.qos import policy as policy_object
from neutron.objects.qos import qos_policy_validator as checker
from neutron.objects.qos import rule as rule_object
from neutron.objects.qos import rule_type as rule_type_object
from neutron.services.qos import constants as qos_constants
from neutron.services.qos.drivers import manager
@ -75,6 +77,7 @@ class QoSPlugin(qos.QoSPluginBase):
qos_rules_alias.ALIAS,
qos_port_network_policy.ALIAS,
qos_pps_rule.ALIAS,
qos_pps_minimum_rule.ALIAS,
]
__native_pagination_support = True
@ -410,7 +413,7 @@ class QoSPlugin(qos.QoSPluginBase):
raise qos_exc.QosRuleNotSupportedByNetwork(
rule_type=rule.rule_type, network_id=network_id)
def reject_min_bw_rule_updates(self, context, policy):
def reject_rule_update_for_bound_port(self, context, policy):
ports = self._get_ports_with_policy(context, policy)
for port in ports:
# NOTE(bence romsics): In some cases the presence of
@ -582,12 +585,15 @@ class QoSPlugin(qos.QoSPluginBase):
policy = policy_object.QosPolicy.get_policy_obj(context, policy_id)
checker.check_bandwidth_rule_conflict(policy, rule_data)
rule = rule_cls(context, qos_policy_id=policy_id, **rule_data)
checker.check_min_pps_rule_conflict(policy, rule)
checker.check_rules_conflict(policy, rule)
rule.create()
policy.obj_load_attr('rules')
self.validate_policy(context, policy)
if rule.rule_type == qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH:
self.reject_min_bw_rule_updates(context, policy)
if rule.rule_type in (
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
self.reject_rule_update_for_bound_port(context, policy)
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
context, policy)
@ -623,12 +629,15 @@ class QoSPlugin(qos.QoSPluginBase):
checker.check_bandwidth_rule_conflict(policy, rule_data)
rule = policy.get_rule_by_id(rule_id)
rule.update_fields(rule_data, reset_changes=True)
checker.check_min_pps_rule_conflict(policy, rule)
checker.check_rules_conflict(policy, rule)
rule.update()
policy.obj_load_attr('rules')
self.validate_policy(context, policy)
if rule.rule_type == qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH:
self.reject_min_bw_rule_updates(context, policy)
if rule.rule_type in (
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
self.reject_rule_update_for_bound_port(context, policy)
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
context, policy)
@ -687,8 +696,10 @@ class QoSPlugin(qos.QoSPluginBase):
rule = policy.get_rule_by_id(rule_id)
rule.delete()
policy.obj_load_attr('rules')
if rule.rule_type == qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH:
self.reject_min_bw_rule_updates(context, policy)
if rule.rule_type in (
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
self.reject_rule_update_for_bound_port(context, policy)
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
context, policy)

View File

@ -233,6 +233,10 @@ def get_random_flow_direction():
return random.choice(constants.VALID_DIRECTIONS)
def get_random_flow_direction_or_any():
return random.choice(constants.VALID_DIRECTIONS_AND_ANY)
def get_random_ha_states():
return random.choice(constants.VALID_HA_STATES)

View File

@ -1002,3 +1002,172 @@ class ProjectReaderQosMinimumBandwidthRuleTests(
def setUp(self):
super(ProjectReaderQosMinimumBandwidthRuleTests, self).setUp()
self.context = self.project_reader_ctx
class SystemAdminQosMinimumPacketRateRuleTests(QosRulesAPITestCase):
def setUp(self):
super(SystemAdminQosMinimumPacketRateRuleTests, self).setUp()
self.context = self.system_admin_ctx
def test_get_policy_minimum_packet_rate_rule(self):
self.assertTrue(
policy.enforce(self.context,
'get_policy_minimum_packet_rate_rule',
self.target))
self.assertTrue(
policy.enforce(self.context,
'get_policy_minimum_packet_rate_rule',
self.alt_target))
def test_create_policy_minimum_packet_rate_rule(self):
self.assertTrue(
policy.enforce(self.context,
'create_policy_minimum_packet_rate_rule',
self.target))
self.assertTrue(
policy.enforce(self.context,
'create_policy_minimum_packet_rate_rule',
self.alt_target))
def test_update_policy_minimum_packet_rate_rule(self):
self.assertTrue(
policy.enforce(self.context,
'update_policy_minimum_packet_rate_rule',
self.target))
self.assertTrue(
policy.enforce(self.context,
'update_policy_minimum_packet_rate_rule',
self.alt_target))
def test_delete_policy_minimum_packet_rate_rule(self):
self.assertTrue(
policy.enforce(self.context,
'delete_policy_minimum_packet_rate_rule',
self.target))
self.assertTrue(
policy.enforce(self.context,
'delete_policy_minimum_packet_rate_rule',
self.alt_target))
class SystemMemberQosMinimumPacketRateRuleTests(
SystemAdminQosMinimumPacketRateRuleTests):
def setUp(self):
super(SystemMemberQosMinimumPacketRateRuleTests, self).setUp()
self.context = self.system_member_ctx
def test_create_policy_minimum_packet_rate_rule(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'create_policy_minimum_packet_rate_rule',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'create_policy_minimum_packet_rate_rule',
self.alt_target)
def test_update_policy_minimum_packet_rate_rule(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'update_policy_minimum_packet_rate_rule',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'update_policy_minimum_packet_rate_rule',
self.alt_target)
def test_delete_policy_minimum_packet_rate_rule(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'delete_policy_minimum_packet_rate_rule',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'delete_policy_minimum_packet_rate_rule',
self.alt_target)
class SystemReaderQosMinimumPacketRateRuleTests(
SystemMemberQosMinimumPacketRateRuleTests):
def setUp(self):
super(SystemReaderQosMinimumPacketRateRuleTests, self).setUp()
self.context = self.system_reader_ctx
class ProjectAdminQosMinimumPacketRateRuleTests(QosRulesAPITestCase):
def setUp(self):
super(ProjectAdminQosMinimumPacketRateRuleTests, self).setUp()
self.context = self.project_admin_ctx
def test_get_policy_minimum_packet_rate_rule(self):
self.assertTrue(
policy.enforce(self.context,
'get_policy_minimum_packet_rate_rule',
self.target))
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'get_policy_minimum_packet_rate_rule',
self.alt_target)
def test_create_policy_minimum_packet_rate_rule(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'create_policy_minimum_packet_rate_rule',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'create_policy_minimum_packet_rate_rule',
self.alt_target)
def test_update_policy_minimum_packet_rate_rule(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'update_policy_minimum_packet_rate_rule',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'update_policy_minimum_packet_rate_rule',
self.alt_target)
def test_delete_policy_minimum_packet_rate_rule(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'delete_policy_minimum_packet_rate_rule',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context, 'delete_policy_minimum_packet_rate_rule',
self.alt_target)
class ProjectMemberQosMinimumPacketRateRuleTests(
ProjectAdminQosMinimumPacketRateRuleTests):
def setUp(self):
super(ProjectMemberQosMinimumPacketRateRuleTests, self).setUp()
self.context = self.project_member_ctx
class ProjectReaderQosMinimumPacketRateRuleTests(
ProjectMemberQosMinimumPacketRateRuleTests):
def setUp(self):
super(ProjectReaderQosMinimumPacketRateRuleTests, self).setUp()
self.context = self.project_reader_ctx

View File

@ -35,6 +35,7 @@ RULE_OBJ_CLS = {
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,
q_consts.RULE_TYPE_MINIMUM_PACKET_RATE: rule.QosMinimumPacketRateRule,
}
@ -101,6 +102,10 @@ class QosPolicyObjectTestCase(test_base.BaseObjectIfaceTestCase):
self.get_random_db_fields(rule.QosMinimumBandwidthRule)
for _ in range(3)]
self.db_qos_minimum_packet_rate_rules = [
self.get_random_db_fields(rule.QosMinimumPacketRateRule)
for _ in range(3)]
self.model_map.update({
self._test_class.db_model: self.db_objs,
binding.QosPolicyPortBinding.db_model: [],
@ -108,7 +113,9 @@ class QosPolicyObjectTestCase(test_base.BaseObjectIfaceTestCase):
rule.QosBandwidthLimitRule.db_model: self.db_qos_bandwidth_rules,
rule.QosDscpMarkingRule.db_model: self.db_qos_dscp_rules,
rule.QosMinimumBandwidthRule.db_model:
self.db_qos_minimum_bandwidth_rules})
self.db_qos_minimum_bandwidth_rules,
rule.QosMinimumPacketRateRule:
self.db_qos_minimum_packet_rate_rules})
# TODO(ihrachys): stop overriding those test cases, instead base test cases
# should be expanded if there are missing bits there to support QoS objects
@ -179,7 +186,8 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
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
q_consts.RULE_TYPE_PACKET_RATE_LIMIT,
q_consts.RULE_TYPE_MINIMUM_PACKET_RATE] and
bwlimit_direction is not None):
rule_fields['direction'] = bwlimit_direction
rule_obj = obj_cls(self.context, **rule_fields)
@ -481,6 +489,22 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
self.assertIn(rule_objs[2], policy_obj_v1_8.rules)
self.assertNotIn(rule_objs[3], policy_obj_v1_8.rules)
def test_object_version_degradation_less_than_1_10(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,
q_consts.RULE_TYPE_MINIMUM_PACKET_RATE], reload_rules=True,
bwlimit_direction=lib_consts.INGRESS_DIRECTION)
policy_obj_v1_9 = self._policy_through_version(policy_obj, '1.9')
self.assertIn(rule_objs[0], policy_obj_v1_9.rules)
self.assertIn(rule_objs[1], policy_obj_v1_9.rules)
self.assertIn(rule_objs[2], policy_obj_v1_9.rules)
self.assertIn(rule_objs[3], policy_obj_v1_9.rules)
self.assertNotIn(rule_objs[4], policy_obj_v1_9.rules)
@mock.patch.object(policy.QosPolicy, 'unset_default')
def test_filter_by_shared(self, *mocks):
project_id = uuidutils.generate_uuid()

View File

@ -290,3 +290,54 @@ class QosPacketRateLimitRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
id=generated_qos_policy_id,
project_id=uuidutils.generate_uuid())
policy_obj.create()
class QosMinimumPacketRateRuleObjectTestCase(
test_base.BaseObjectIfaceTestCase):
_test_class = rule.QosMinimumPacketRateRule
def test_to_dict_returns_type(self):
obj = rule.QosMinimumPacketRateRule(self.context, **self.db_objs[0])
dict_ = obj.to_dict()
self.assertEqual(qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE,
dict_['type'])
def test_duplicate_rules(self):
policy_id = uuidutils.generate_uuid()
ingress_rule_1 = rule.QosMinimumPacketRateRule(
self.context, qos_policy_id=policy_id,
min_kpps=1000, direction=constants.INGRESS_DIRECTION)
ingress_rule_2 = rule.QosMinimumPacketRateRule(
self.context, qos_policy_id=policy_id,
min_kpps=2000, direction=constants.INGRESS_DIRECTION)
egress_rule = rule.QosMinimumPacketRateRule(
self.context, qos_policy_id=policy_id,
min_kpps=1000, direction=constants.EGRESS_DIRECTION)
directionless_rule = rule.QosMinimumPacketRateRule(
self.context, qos_policy_id=policy_id,
min_kpps=1000, direction=constants.ANY_DIRECTION)
min_bw_rule = rule.QosMinimumBandwidthRule(
self.context, qos_policy_id=policy_id,
min_kbps=1000, direction=constants.INGRESS_DIRECTION)
self.assertTrue(ingress_rule_1.duplicates(ingress_rule_2))
self.assertFalse(ingress_rule_1.duplicates(egress_rule))
self.assertFalse(ingress_rule_1.duplicates(directionless_rule))
self.assertFalse(ingress_rule_1.duplicates(min_bw_rule))
class QosMinimumPacketRateRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
testlib_api.SqlTestCase):
_test_class = rule.QosMinimumPacketRateRule
def setUp(self):
super(QosMinimumPacketRateRuleDbObjectTestCase, 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()

View File

@ -511,6 +511,8 @@ FIELD_TYPE_VALUE_GENERATOR_MAP = {
common_types.EtherTypeEnumField: tools.get_random_ether_type,
common_types.FloatingIPStatusEnumField: tools.get_random_floatingip_status,
common_types.FlowDirectionEnumField: tools.get_random_flow_direction,
common_types.FlowDirectionAndAnyEnumField:
tools.get_random_flow_direction_or_any,
common_types.HARouterEnumField: tools.get_random_ha_states,
common_types.IpamAllocationStatusEnumField: tools.get_random_ipam_status,
common_types.IPNetworkField: lib_test_tools.get_random_ip_network,

View File

@ -82,14 +82,15 @@ object_data = {
'PortUplinkStatusPropagation': '1.1-f0a4ca451a941910376c33616dea5de2',
'ProviderResourceAssociation': '1.0-05ab2d5a3017e5ce9dd381328f285f34',
'ProvisioningBlock': '1.0-c19d6d05bfa8143533471c1296066125',
'QosBandwidthLimitRule': '1.4-51b662b12a8d1dfa89288d826c6d26d3',
'QosDscpMarkingRule': '1.4-0313c6554b34fd10c753cb63d638256c',
'QosMinimumBandwidthRule': '1.4-314c3419f4799067cc31cc319080adff',
'QosPacketRateLimitRule': '1.4-18411fa95f54602b8c8a5da2d3194b31',
'QosBandwidthLimitRule': '1.5-51b662b12a8d1dfa89288d826c6d26d3',
'QosDscpMarkingRule': '1.5-0313c6554b34fd10c753cb63d638256c',
'QosMinimumBandwidthRule': '1.5-314c3419f4799067cc31cc319080adff',
'QosMinimumPacketRateRule': '1.5-d0516c55aa2f310a2646c7d243cb8620',
'QosPacketRateLimitRule': '1.5-18411fa95f54602b8c8a5da2d3194b31',
'QosPolicyRBAC': '1.1-192845c5ed0718e1c54fac36936fcd7d',
'QosRuleType': '1.4-a5b870dfa6f510a91f5cb0216873064e',
'QosRuleType': '1.5-56b25ec81e27aa5c8238b8c43e88aed6',
'QosRuleTypeDriver': '1.0-7d8cb9f0ef661ac03700eae97118e3db',
'QosPolicy': '1.9-4adb0cde3102c10d8970ec9487fd7fe7',
'QosPolicy': '1.10-4adb0cde3102c10d8970ec9487fd7fe7',
'QosPolicyDefault': '1.0-59e5060eedb1f06dd0935a244d27d11c',
'QosPolicyFloatingIPBinding': '1.0-5625df4205a18778cd6aa40f99be024e',
'QosPolicyRouterGatewayIPBinding': '1.0-da064fbfe5ee18c950b905b483bf59e3',

View File

@ -103,7 +103,12 @@ class TestQosPlugin(base.BaseQosTestCase):
'packet_rate_limit_rule': {
'id': uuidutils.generate_uuid(),
'max_kpps': 20,
'max_burst_kpps': 130}}
'max_burst_kpps': 130},
'minimum_packet_rate_rule': {
'id': uuidutils.generate_uuid(),
'min_kpps': 10,
'direction': 'any'},
}
self.policy = policy_object.QosPolicy(
self.ctxt, **self.policy_data['policy'])
@ -114,12 +119,15 @@ class TestQosPlugin(base.BaseQosTestCase):
self.dscp_rule = rule_object.QosDscpMarkingRule(
self.ctxt, **self.rule_data['dscp_marking_rule'])
self.min_rule = rule_object.QosMinimumBandwidthRule(
self.min_bw_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'])
self.min_pps_rule = rule_object.QosMinimumPacketRateRule(
self.ctxt, **self.rule_data['minimum_packet_rate_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)
@ -158,8 +166,8 @@ class TestQosPlugin(base.BaseQosTestCase):
port_res, self.port)
def test__extend_port_resource_request_min_bw_rule(self):
self.min_rule.direction = lib_constants.EGRESS_DIRECTION
port = self._create_and_extend_port([self.min_rule])
self.min_bw_rule.direction = lib_constants.EGRESS_DIRECTION
port = self._create_and_extend_port([self.min_bw_rule])
self.assertEqual(
['CUSTOM_PHYSNET_PUBLIC', 'CUSTOM_VNIC_TYPE_NORMAL'],
@ -171,16 +179,17 @@ class TestQosPlugin(base.BaseQosTestCase):
)
def test__extend_port_resource_request_mixed_rules(self):
self.min_rule.direction = lib_constants.EGRESS_DIRECTION
self.min_bw_rule.direction = lib_constants.EGRESS_DIRECTION
min_rule_ingress_data = {
min_bw_rule_ingress_data = {
'id': uuidutils.generate_uuid(),
'min_kbps': 20,
'direction': lib_constants.INGRESS_DIRECTION}
min_rule_ingress = rule_object.QosMinimumBandwidthRule(
self.ctxt, **min_rule_ingress_data)
min_bw_rule_ingress = rule_object.QosMinimumBandwidthRule(
self.ctxt, **min_bw_rule_ingress_data)
port = self._create_and_extend_port([self.min_rule, min_rule_ingress])
port = self._create_and_extend_port(
[self.min_bw_rule, min_bw_rule_ingress])
self.assertEqual(
['CUSTOM_PHYSNET_PUBLIC', 'CUSTOM_VNIC_TYPE_NORMAL'],
port['resource_request']['required']
@ -199,9 +208,9 @@ class TestQosPlugin(base.BaseQosTestCase):
self.assertIsNone(port.get('resource_request'))
def test__extend_port_resource_request_non_provider_net(self):
self.min_rule.direction = lib_constants.EGRESS_DIRECTION
self.min_bw_rule.direction = lib_constants.EGRESS_DIRECTION
port = self._create_and_extend_port([self.min_rule],
port = self._create_and_extend_port([self.min_bw_rule],
physical_network=None)
self.assertIsNone(port.get('resource_request'))
@ -211,10 +220,10 @@ class TestQosPlugin(base.BaseQosTestCase):
self.assertIsNone(port.get('resource_request'))
def test__extend_port_resource_request_inherited_policy(self):
self.min_rule.direction = lib_constants.EGRESS_DIRECTION
self.min_rule.qos_policy_id = self.policy.id
self.min_bw_rule.direction = lib_constants.EGRESS_DIRECTION
self.min_bw_rule.qos_policy_id = self.policy.id
port = self._create_and_extend_port([self.min_rule],
port = self._create_and_extend_port([self.min_bw_rule],
has_net_qos_policy=True)
self.assertEqual(
['CUSTOM_PHYSNET_PUBLIC', 'CUSTOM_VNIC_TYPE_NORMAL'],
@ -413,7 +422,7 @@ class TestQosPlugin(base.BaseQosTestCase):
def test_create_min_bw_rule_on_bound_port(self):
policy = self._get_policy()
policy.rules = [self.min_rule]
policy.rules = [self.min_bw_rule]
segment = network_object.NetworkSegment(
physical_network='fake physnet')
net = network_object.Network(
@ -441,7 +450,7 @@ class TestQosPlugin(base.BaseQosTestCase):
def test_create_min_bw_rule_on_unbound_port(self):
policy = self._get_policy()
policy.rules = [self.min_rule]
policy.rules = [self.min_bw_rule]
segment = network_object.NetworkSegment(
physical_network='fake physnet')
net = network_object.Network(
@ -574,9 +583,12 @@ class TestQosPlugin(base.BaseQosTestCase):
mock_manager.attach_mock(mock_qos_rule_create, 'create')
mock_manager.attach_mock(self.qos_plugin.driver_manager, 'driver')
mock_manager.reset_mock()
with mock.patch(
'neutron.objects.qos.qos_policy_validator'
'.check_bandwidth_rule_conflict', return_value=None):
with mock.patch('neutron.objects.qos.qos_policy_validator'
'.check_bandwidth_rule_conflict',
return_value=None), \
mock.patch(
'neutron.objects.qos.qos_policy_validator'
'.check_min_pps_rule_conflict', return_value=None):
self.qos_plugin.create_policy_bandwidth_limit_rule(
self.ctxt, self.policy.id, self.rule_data)
self._validate_driver_params('update_policy', self.ctxt)
@ -603,7 +615,7 @@ class TestQosPlugin(base.BaseQosTestCase):
def test_create_policy_rule_check_rule_max_more_than_min(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_rule])
setattr(_policy, "rules", [self.min_bw_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy) as mock_qos_get_obj:
self.qos_plugin.create_policy_bandwidth_limit_rule(
@ -615,7 +627,7 @@ class TestQosPlugin(base.BaseQosTestCase):
def test_create_policy_rule_check_rule_bwlimit_less_than_minbw(self):
_policy = self._get_policy()
self.rule_data['bandwidth_limit_rule']['max_kbps'] = 1
setattr(_policy, "rules", [self.min_rule])
setattr(_policy, "rules", [self.min_bw_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy) as mock_qos_get_obj:
self.assertRaises(qos_exc.QoSRuleParameterConflict,
@ -690,13 +702,13 @@ class TestQosPlugin(base.BaseQosTestCase):
self.mock_qos_load_attr.assert_called_once_with('rules')
self._validate_driver_params('update_policy', self.ctxt)
rules = [self.rule, self.min_rule]
rules = [self.rule, self.min_bw_rule]
setattr(_policy, "rules", rules)
self.mock_qos_load_attr.reset_mock()
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.qos_plugin.update_policy_minimum_bandwidth_rule(
self.ctxt, self.min_rule.id,
self.ctxt, self.min_bw_rule.id,
self.policy.id, self.rule_data)
self.mock_qos_load_attr.assert_called_once_with('rules')
self._validate_driver_params('update_policy', self.ctxt)
@ -716,16 +728,17 @@ class TestQosPlugin(base.BaseQosTestCase):
self.assertRaises(
qos_exc.QoSRuleParameterConflict,
self.qos_plugin.update_policy_minimum_bandwidth_rule,
self.ctxt, self.min_rule.id,
self.ctxt, self.min_bw_rule.id,
self.policy.id, self.rule_data)
def test_update_policy_rule_check_rule_minbw_gr_than_bwlimit(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_rule])
setattr(_policy, "rules", [self.min_bw_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.qos_plugin.update_policy_minimum_bandwidth_rule(
self.ctxt, self.min_rule.id, self.policy.id, self.rule_data)
self.ctxt, self.min_bw_rule.id, self.policy.id,
self.rule_data)
self.mock_qos_load_attr.assert_called_once_with('rules')
self._validate_driver_params('update_policy', self.ctxt)
self.rule_data['bandwidth_limit_rule']['max_kbps'] = 1
@ -1260,6 +1273,314 @@ class TestQosPlugin(base.BaseQosTestCase):
self.qos_plugin.get_rule_type,
self.ctxt, qos_constants.RULE_TYPE_PACKET_RATE_LIMIT)
def test_create_min_pps_rule_on_bound_port(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_pps_rule])
segment = network_object.NetworkSegment(
physical_network='fake physnet')
net = network_object.Network(
self.ctxt,
segments=[segment])
port = ports_object.Port(
self.ctxt,
id=uuidutils.generate_uuid(),
network_id=uuidutils.generate_uuid(),
device_owner='compute:fake-zone')
with mock.patch(
'neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy), \
mock.patch(
'neutron.objects.network.Network.get_object',
return_value=net), \
mock.patch.object(
self.qos_plugin,
'_get_ports_with_policy',
return_value=[port]):
self.assertRaises(
NotImplementedError,
self.qos_plugin.create_policy_minimum_packet_rate_rule,
self.ctxt, _policy.id, self.rule_data)
def test_create_min_pps_rule_on_unbound_port(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_pps_rule])
segment = network_object.NetworkSegment(
physical_network='fake physnet')
net = network_object.Network(
self.ctxt,
segments=[segment])
port = ports_object.Port(
self.ctxt,
id=uuidutils.generate_uuid(),
network_id=uuidutils.generate_uuid(),
device_owner='')
with mock.patch(
'neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy), \
mock.patch(
'neutron.objects.network.Network.get_object',
return_value=net), \
mock.patch.object(
self.qos_plugin,
'_get_ports_with_policy',
return_value=[port]):
try:
self.qos_plugin.create_policy_minimum_packet_rate_rule(
self.ctxt, _policy.id, self.rule_data)
except NotImplementedError:
self.fail()
def test_create_policy_rule_check_rule_min_pps_direction_conflict(self):
_policy = self._get_policy()
self.rule_data['minimum_packet_rate_rule']['direction'] = 'any'
setattr(_policy, "rules", [self.min_pps_rule])
rules = [
{
'minimum_packet_rate_rule': {
'id': uuidutils.generate_uuid(),
'min_kpps': 10,
'direction': 'ingress'
}
},
{
'minimum_packet_rate_rule': {
'id': uuidutils.generate_uuid(),
'min_kpps': 10,
'direction': 'egress'
}
},
]
for new_rule_data in rules:
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy) as mock_qos_get_obj:
self.assertRaises(qos_exc.QoSRuleParameterConflict,
self.qos_plugin.create_policy_minimum_packet_rate_rule,
self.ctxt, self.policy.id, new_rule_data)
mock_qos_get_obj.assert_called_once_with(self.ctxt,
id=_policy.id)
for rule_data in rules:
min_pps_rule = rule_object.QosMinimumPacketRateRule(
self.ctxt, **rule_data['minimum_packet_rate_rule'])
setattr(_policy, "rules", [min_pps_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy) as mock_qos_get_obj:
self.assertRaises(qos_exc.QoSRuleParameterConflict,
self.qos_plugin.create_policy_minimum_packet_rate_rule,
self.ctxt, self.policy.id, self.rule_data)
mock_qos_get_obj.assert_called_once_with(self.ctxt,
id=_policy.id)
def test_create_policy_min_pps_rule(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_pps_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.qos_plugin.create_policy_minimum_packet_rate_rule(
self.ctxt, self.policy.id, self.rule_data)
self._validate_driver_params('update_policy', self.ctxt)
def test_create_policy_min_pps_rule_duplicates(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_pps_rule])
new_rule_data = {
'minimum_packet_rate_rule': {
'id': uuidutils.generate_uuid(),
'min_kpps': 1234,
'direction': self.min_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_minimum_packet_rate_rule,
self.ctxt, _policy.id, new_rule_data)
mock_qos_get_obj.assert_called_once_with(self.ctxt, id=_policy.id)
def test_create_policy_min_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_minimum_packet_rate_rule,
self.ctxt, self.policy.id, self.rule_data)
def test_update_policy_min_pps_rule(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_pps_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.qos_plugin.update_policy_minimum_packet_rate_rule(
self.ctxt, self.min_pps_rule.id, self.policy.id,
self.rule_data)
self._validate_driver_params('update_policy', self.ctxt)
def test_update_policy_rule_check_rule_min_pps_direction_conflict(self):
_policy = self._get_policy()
rules_data = [
{
'minimum_packet_rate_rule': {
'id': uuidutils.generate_uuid(),
'min_kpps': 10,
'direction': 'ingress'
}
},
{
'minimum_packet_rate_rule': {
'id': uuidutils.generate_uuid(),
'min_kpps': 10,
'direction': 'egress'
}
},
]
self.rule_data['minimum_packet_rate_rule']['direction'] = 'any'
for rule_data in rules_data:
rules = [
rule_object.QosMinimumPacketRateRule(
self.ctxt, **rules_data[0]['minimum_packet_rate_rule']),
rule_object.QosMinimumPacketRateRule(
self.ctxt, **rules_data[1]['minimum_packet_rate_rule']),
]
setattr(_policy, 'rules', rules)
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy) as mock_qos_get_obj:
self.assertRaises(qos_exc.QoSRuleParameterConflict,
self.qos_plugin.update_policy_minimum_packet_rate_rule,
self.ctxt, rule_data['minimum_packet_rate_rule']['id'],
self.policy.id, self.rule_data)
mock_qos_get_obj.assert_called_once_with(self.ctxt,
id=_policy.id)
def test_update_policy_min_pps_rule_bad_policy(self):
_policy = self._get_policy()
setattr(_policy, "rules", [])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.assertRaises(
qos_exc.QosRuleNotFound,
self.qos_plugin.update_policy_minimum_packet_rate_rule,
self.ctxt, self.min_pps_rule.id, self.policy.id,
self.rule_data)
def test_update_policy_min_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_minimum_packet_rate_rule,
self.ctxt, self.min_pps_rule.id, self.policy.id,
self.rule_data)
def test_delete_policy_min_pps_rule(self):
_policy = self._get_policy()
setattr(_policy, "rules", [self.min_pps_rule])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.qos_plugin.delete_policy_minimum_packet_rate_rule(
self.ctxt, self.min_pps_rule.id, self.policy.id)
self._validate_driver_params('update_policy', self.ctxt)
def test_delete_policy_min_pps_rule_bad_policy(self):
_policy = self._get_policy()
setattr(_policy, "rules", [])
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=_policy):
self.assertRaises(
qos_exc.QosRuleNotFound,
self.qos_plugin.delete_policy_minimum_packet_rate_rule,
self.ctxt, self.min_pps_rule.id, _policy.id)
def test_delete_policy_min_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_minimum_packet_rate_rule,
self.ctxt, self.min_pps_rule.id, self.policy.id)
def test_get_policy_min_pps_rule(self):
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
return_value=self.policy):
with mock.patch('neutron.objects.qos.rule.'
'QosMinimumPacketRateRule.'
'get_object') as get_object_mock:
self.qos_plugin.get_policy_minimum_packet_rate_rule(
self.ctxt, self.min_pps_rule.id, self.policy.id)
get_object_mock.assert_called_once_with(
self.ctxt, id=self.min_pps_rule.id)
def test_get_policy_min_pps_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.'
'QosMinimumPacketRateRule.'
'get_objects') as get_objects_mock:
self.qos_plugin.get_policy_minimum_packet_rate_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_min_pps_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.'
'QosMinimumPacketRateRule.'
'get_objects') as get_objects_mock:
filters = {'filter': 'filter_id'}
self.qos_plugin.get_policy_minimum_packet_rate_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_min_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.get_policy_minimum_packet_rate_rule,
self.ctxt, self.min_pps_rule.id, self.policy.id)
def test_get_policy_min_pps_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_minimum_packet_rate_rules,
self.ctxt, self.policy.id)
def test_get_min_pps_rule_type(self):
admin_ctxt = context.get_admin_context()
drivers_details = [{
'name': 'fake-driver',
'supported_parameters': [{
'parameter_name': 'min_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_MINIMUM_PACKET_RATE)
self.assertEqual(
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE,
rule_type_details['type'])
self.assertEqual(
drivers_details, rule_type_details['drivers'])
def test_get_min_pps_rule_type_as_user(self):
self.assertRaises(
lib_exc.NotAuthorized,
self.qos_plugin.get_rule_type,
self.ctxt, qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE)
class QoSRuleAliasTestExtensionManager(object):

View File

@ -0,0 +1,5 @@
---
features:
- |
Added new API extension to QoS service plugin to support CRUD operations
for minimum packet rate rule in Neutron server.

View File

@ -235,6 +235,7 @@ neutron.objects =
QosBandwidthLimitRule = neutron.objects.qos.rule:QosBandwidthLimitRule
QosDscpMarkingRule = neutron.objects.qos.rule:QosDscpMarkingRule
QosMinimumBandwidthRule = neutron.objects.qos.rule:QosMinimumBandwidthRule
QosMinimumPacketRateRule = neutron.objects.qos.rule:QosMinimumPacketRateRule
QosPacketRateLimitRule = neutron.objects.qos.rule:QosPacketRateLimitRule
QosPolicy = neutron.objects.qos.policy:QosPolicy
QosPolicyDefault = neutron.objects.qos.policy:QosPolicyDefault