Merge "Support filtering for QoS rule type list"

This commit is contained in:
Zuul 2022-03-15 15:42:10 +00:00 committed by Gerrit Code Review
commit fd4db01242
10 changed files with 101 additions and 84 deletions

View File

@ -98,7 +98,7 @@ NotImplemented.
Supported QoS rule types
~~~~~~~~~~~~~~~~~~~~~~~~
Each QoS driver has a property called supported_rule_types, where the driver
Each QoS driver has a member called ``supported_rules``, where the driver
exposes the rules it's able to handle.
For a list of all rule types, see:

View File

@ -52,6 +52,7 @@ from neutron_lib.api.definitions import qos
from neutron_lib.api.definitions import qos_bw_limit_direction
from neutron_lib.api.definitions import qos_default
from neutron_lib.api.definitions import qos_rule_type_details
from neutron_lib.api.definitions import qos_rule_type_filter
from neutron_lib.api.definitions import qos_rules_alias
from neutron_lib.api.definitions import quota_check_limit
from neutron_lib.api.definitions import rbac_address_scope
@ -124,6 +125,7 @@ ML2_SUPPORTED_API_EXTENSIONS = [
qos_bw_limit_direction.ALIAS,
qos_default.ALIAS,
qos_rule_type_details.ALIAS,
qos_rule_type_filter.ALIAS,
qos_rules_alias.ALIAS,
'quotas',
quota_check_limit.ALIAS,

View File

@ -0,0 +1,20 @@
# Copyright (c) 2022 Red Hat, Inc.
#
# 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_rule_type_filter as apidef
from neutron_lib.api import extensions
class Qos_rule_type_filter(extensions.APIExtensionDescriptor):
api_definition = apidef

View File

@ -60,13 +60,14 @@ class QosRuleType(base.NeutronObject):
# we don't receive context because we don't need db access at all
@classmethod
def get_objects(cls, validate_filters=True, **kwargs):
all_supported = kwargs.pop('all_supported', None)
all_rules = kwargs.pop('all_rules', None)
if validate_filters:
cls.validate_filters(**kwargs)
rule_types = (
directory.get_plugin(alias=constants.QOS).supported_rule_types)
# TODO(ihrachys): apply filters to returned result
rule_types = directory.get_plugin(
alias=constants.QOS).supported_rule_types(
all_supported=all_supported, all_rules=all_rules)
return [cls(type=type_) for type_ in rule_types]
# we don't receive context because we don't need db access at all

View File

@ -163,15 +163,24 @@ class QosServiceDriverManager(object):
return False
@property
def supported_rule_types(self):
def supported_rule_types(self, all_supported=None, all_rules=None):
rule_types = set(qos_consts.VALID_RULE_TYPES)
if all_rules:
LOG.debug('All supported QoS rule types: %s', rule_types)
return rule_types
if not self._drivers:
return []
rule_types = set(qos_consts.VALID_RULE_TYPES)
# Recalculate on every call to allow drivers determine supported rule
# types dynamically
if all_supported:
rule_types = set.union(*[set(driver.supported_rules) for driver in
self._drivers])
LOG.debug('All QoS rule types supported by at least one loaded '
'driver: %s', rule_types)
return rule_types
for driver in self._drivers:
new_rule_types = rule_types & set(driver.supported_rules)
dropped_rule_types = rule_types - new_rule_types

View File

@ -31,6 +31,7 @@ from neutron_lib.api.definitions import qos_pps_minimum_rule
from neutron_lib.api.definitions import qos_pps_minimum_rule_alias
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_rule_type_filter
from neutron_lib.api.definitions import qos_rules_alias
from neutron_lib.callbacks import events as callbacks_events
from neutron_lib.callbacks import registry as callbacks_registry
@ -126,6 +127,7 @@ class QoSPlugin(qos.QoSPluginBase):
qos_bw_limit_direction.ALIAS,
qos_default.ALIAS,
qos_rule_type_details.ALIAS,
qos_rule_type_filter.ALIAS,
port_resource_request.ALIAS,
port_resource_request_groups.ALIAS,
qos_bw_minimum_ingress.ALIAS,
@ -882,9 +884,9 @@ class QoSPlugin(qos.QoSPluginBase):
def supported_rule_type_details(self, rule_type_name):
return self.driver_manager.supported_rule_type_details(rule_type_name)
@property
def supported_rule_types(self):
return self.driver_manager.supported_rule_types
def supported_rule_types(self, all_supported=None, all_rules=None):
return self.driver_manager.supported_rule_types(
all_supported=all_supported, all_rules=all_rules)
@db_base_plugin_common.convert_result_to_dict
def create_policy_rule(self, context, rule_cls, policy_id, rule_data):

View File

@ -77,10 +77,8 @@ class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT, rule_type_details.type)
def test_get_objects(self):
rule_types_mock = mock.PropertyMock(
return_value=set(qos_consts.VALID_RULE_TYPES))
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
new_callable=rule_types_mock):
return_value=set(qos_consts.VALID_RULE_TYPES)):
types = rule_type.QosRuleType.get_objects()
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
sorted(type_['type'] for type_ in types))

View File

@ -10,9 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import itertools
from unittest import mock
from neutron_lib.api.definitions import portbindings
from neutron_lib.callbacks import registry
from neutron_lib import constants as lib_consts
from neutron_lib import context
from neutron_lib import exceptions
@ -20,9 +22,14 @@ from neutron_lib.services.qos import base as qos_driver_base
from neutron_lib.services.qos import constants as qos_consts
from oslo_utils import uuidutils
from neutron.api.rpc.callbacks.producer import registry as rpc_registry
from neutron.objects import ports as ports_object
from neutron.objects.qos import rule as rule_object
from neutron.services.qos.drivers.linuxbridge import driver as lb_driver
from neutron.services.qos.drivers import manager as driver_mgr
from neutron.services.qos.drivers.openvswitch import driver as ovs_driver
from neutron.services.qos.drivers.ovn import driver as ovn_driver
from neutron.services.qos.drivers.sriov import driver as sriov_driver
from neutron.tests.unit.services.qos import base
@ -32,9 +39,14 @@ class TestQosDriversManagerBase(base.BaseQosTestCase):
super(TestQosDriversManagerBase, self).setUp()
self.config_parse()
self.setup_coreplugin(load_plugins=False)
self._loaded_qos_drivers = []
@staticmethod
def _create_manager_with_drivers(drivers_details):
def _delete_loaded_qos_drivers(self):
registry._get_callback_manager().clear()
for idx, _ in enumerate(self._loaded_qos_drivers):
del self._loaded_qos_drivers[idx]
def _create_manager_with_drivers(self, drivers_details):
for name, driver_details in drivers_details.items():
class QoSDriver(qos_driver_base.DriverBase):
@ -43,10 +55,11 @@ class TestQosDriversManagerBase(base.BaseQosTestCase):
return driver_details['is_loaded']
# the new ad-hoc driver will register on the QOS_PLUGIN registry
QoSDriver(name,
driver_details.get('vif_types', []),
driver_details.get('vnic_types', []),
driver_details.get('rules', []))
self._loaded_qos_drivers.append(
QoSDriver(name,
driver_details.get('vif_types', []),
driver_details.get('vnic_types', []),
driver_details.get('rules', [])))
return driver_mgr.QosServiceDriverManager()
@ -169,67 +182,30 @@ class TestQoSDriversRulesValidations(TestQosDriversManagerBase):
class TestQosDriversManagerRules(TestQosDriversManagerBase):
"""Test supported rules"""
def test_available_rules_one_in_common(self):
driver_manager = self._create_manager_with_drivers({
'driver-A': {
'is_loaded': True,
'rules': {
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: {
"max_kbps": {'type:values': None},
"max_burst_kbps": {'type:values': None}
},
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: {
"min_kbps": {'type:values': None},
'direction': {
'type:values': lib_consts.VALID_DIRECTIONS}
}
}
},
'driver-B': {
'is_loaded': True,
'rules': {
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: {
"min_kbps": {'type:values': None},
'direction': {
'type:values': lib_consts.VALID_DIRECTIONS}
},
qos_consts.RULE_TYPE_DSCP_MARKING: {
"dscp_mark": {
'type:values': lib_consts.VALID_DSCP_MARKS}
}
}
}
})
self.assertEqual(driver_manager.supported_rule_types,
set([qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH]))
def test_available_rules_no_rule_in_common(self):
driver_manager = self._create_manager_with_drivers({
'driver-A': {
'is_loaded': True,
'rules': {
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: {
"max_kbps": {'type:values': None},
"max_burst_kbps": {'type:values': None}
}
}
},
'driver-B': {
'is_loaded': True,
'rules': {
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: {
"min_kbps": {'type:values': None},
'direction': {
'type:values': lib_consts.VALID_DIRECTIONS}
},
qos_consts.RULE_TYPE_DSCP_MARKING: {
"dscp_mark": {
'type:values': lib_consts.VALID_DSCP_MARKS}
}
}
}
})
self.assertEqual(driver_manager.supported_rule_types, set([]))
@mock.patch.object(rpc_registry, 'provide')
def test_available_rules(self, *args):
available_drivers = {'linuxbridge': lb_driver.SUPPORTED_RULES,
'ovs': ovs_driver.SUPPORTED_RULES,
'ovn': ovn_driver.SUPPORTED_RULES,
'sriov': sriov_driver.SUPPORTED_RULES}
for drivers in itertools.combinations(available_drivers, 2):
rules_0 = set(available_drivers[drivers[0]])
rules_1 = set(available_drivers[drivers[1]])
driver_manager = self._create_manager_with_drivers(
{drivers[0]: {'is_loaded': True, 'rules': rules_0},
drivers[1]: {'is_loaded': True, 'rules': rules_1}})
self.assertEqual(
driver_manager.supported_rule_types(),
rules_0 & rules_1)
self.assertEqual(
driver_manager.supported_rule_types(all_supported=True),
rules_0 | rules_1)
self.assertEqual(
driver_manager.supported_rule_types(all_rules=True),
set(qos_consts.VALID_RULE_TYPES))
self._delete_loaded_qos_drivers()
def test__parse_parameter_values(self):
range_parameter = {'type:range': [0, 10]}

View File

@ -1310,11 +1310,9 @@ class TestQosPlugin(base.BaseQosTestCase):
self.ctxt, qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
def test_get_rule_types(self):
rule_types_mock = mock.PropertyMock(
return_value=qos_consts.VALID_RULE_TYPES)
filters = {'type': 'type_id'}
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
new_callable=rule_types_mock):
return_value=qos_consts.VALID_RULE_TYPES):
types = self.qos_plugin.get_rule_types(self.ctxt, filters=filters)
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
sorted(type_['type'] for type_ in types))

View File

@ -0,0 +1,11 @@
---
features:
- |
QoS rule type list accepts two filter flags:
* ``all_supported``: if True, the listing call will print all QoS
rule types supported by at least one loaded mechanism driver.
* ``all_rules``: if True, the listing call will print all QoS rule
types supported by the Neutron server.
Both filter flags are exclusive and not required.