Merge "Support filtering for QoS rule type list"
This commit is contained in:
commit
fd4db01242
@ -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:
|
||||
|
@ -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,
|
||||
|
20
neutron/extensions/qos_rule_type_filter.py
Normal file
20
neutron/extensions/qos_rule_type_filter.py
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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))
|
||||
|
@ -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]}
|
||||
|
@ -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))
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user