Merge "New API call to get details of supported QoS rule type"
This commit is contained in:
commit
bea5cd24a9
@ -165,3 +165,7 @@ PORT_BINDING_STATUS_ACTIVE = 'ACTIVE'
|
|||||||
PORT_BINDING_STATUS_INACTIVE = 'INACTIVE'
|
PORT_BINDING_STATUS_INACTIVE = 'INACTIVE'
|
||||||
PORT_BINDING_STATUSES = (PORT_BINDING_STATUS_ACTIVE,
|
PORT_BINDING_STATUSES = (PORT_BINDING_STATUS_ACTIVE,
|
||||||
PORT_BINDING_STATUS_INACTIVE)
|
PORT_BINDING_STATUS_INACTIVE)
|
||||||
|
|
||||||
|
# Possible types of values (e.g. in QoS rule types)
|
||||||
|
VALUES_TYPE_CHOICES = "choices"
|
||||||
|
VALUES_TYPE_RANGE = "range"
|
||||||
|
@ -48,6 +48,8 @@ QOS_RULE_COMMON_FIELDS = {
|
|||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RULE_TYPES = "rule_types"
|
||||||
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
COLLECTION_NAME: {
|
COLLECTION_NAME: {
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
@ -66,7 +68,7 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'rules': {'allow_post': False, 'allow_put': False, 'is_visible': True},
|
'rules': {'allow_post': False, 'allow_put': False, 'is_visible': True},
|
||||||
},
|
},
|
||||||
'rule_types': {
|
RULE_TYPES: {
|
||||||
'type': {'allow_post': False, 'allow_put': False,
|
'type': {'allow_post': False, 'allow_put': False,
|
||||||
'is_visible': True}
|
'is_visible': True}
|
||||||
}
|
}
|
||||||
@ -309,6 +311,10 @@ class QoSPluginBase(service_base.ServicePluginBase):
|
|||||||
def get_plugin_type(cls):
|
def get_plugin_type(cls):
|
||||||
return constants.QOS
|
return constants.QOS
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_rule_type(self, context, rule_type_name, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_rule_types(self, context, filters=None, fields=None, sorts=None,
|
def get_rule_types(self, context, filters=None, fields=None, sorts=None,
|
||||||
limit=None, marker=None, page_reverse=False):
|
limit=None, marker=None, page_reverse=False):
|
||||||
|
74
neutron/extensions/qos_rule_type_details.py
Normal file
74
neutron/extensions/qos_rule_type_details.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Copyright (c) 2017 OVH SAS
|
||||||
|
# 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 import extensions as api_extensions
|
||||||
|
|
||||||
|
from neutron.extensions import qos
|
||||||
|
|
||||||
|
|
||||||
|
# The name of the extension.
|
||||||
|
NAME = "Details of QoS rule types"
|
||||||
|
|
||||||
|
# The alias of the extension.
|
||||||
|
ALIAS = "qos-rule-type-details"
|
||||||
|
|
||||||
|
# The description of the extension.
|
||||||
|
DESCRIPTION = ("Expose details about QoS rule types supported by loaded "
|
||||||
|
"backend drivers")
|
||||||
|
|
||||||
|
# The list of required extensions.
|
||||||
|
REQUIRED_EXTENSIONS = [qos.ALIAS]
|
||||||
|
|
||||||
|
# The list of optional extensions.
|
||||||
|
OPTIONAL_EXTENSIONS = None
|
||||||
|
|
||||||
|
# The resource attribute map for the extension.
|
||||||
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
|
qos.RULE_TYPES: {
|
||||||
|
'drivers': {'allow_post': False, 'allow_put': False,
|
||||||
|
'is_visible': True}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Qos_rule_type_details(api_extensions.ExtensionDescriptor):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return NAME
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return ALIAS
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return DESCRIPTION
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2017-06-22T10:00:00-00:00"
|
||||||
|
|
||||||
|
def get_required_extensions(self):
|
||||||
|
return REQUIRED_EXTENSIONS or []
|
||||||
|
|
||||||
|
def get_optional_extensions(self):
|
||||||
|
return OPTIONAL_EXTENSIONS or []
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
if version == "2.0":
|
||||||
|
return RESOURCE_ATTRIBUTE_MAP
|
||||||
|
else:
|
||||||
|
return {}
|
@ -13,10 +13,12 @@
|
|||||||
from neutron.plugins.common import constants
|
from neutron.plugins.common import constants
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import versionutils
|
||||||
from oslo_versionedobjects import base as obj_base
|
from oslo_versionedobjects import base as obj_base
|
||||||
from oslo_versionedobjects import fields as obj_fields
|
from oslo_versionedobjects import fields as obj_fields
|
||||||
|
|
||||||
from neutron.objects import base
|
from neutron.objects import base
|
||||||
|
from neutron.objects import common_types
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -35,12 +37,29 @@ class QosRuleType(base.NeutronObject):
|
|||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
# Version 1.1: Added QosDscpMarkingRule
|
# Version 1.1: Added QosDscpMarkingRule
|
||||||
# Version 1.2: Added QosMinimumBandwidthRule
|
# Version 1.2: Added QosMinimumBandwidthRule
|
||||||
VERSION = '1.2'
|
# Version 1.3: Added drivers field
|
||||||
|
VERSION = '1.3'
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'type': RuleTypeField(),
|
'type': RuleTypeField(),
|
||||||
|
'drivers': obj_fields.ListOfObjectsField(
|
||||||
|
'QosRuleTypeDriver', nullable=True)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synthetic_fields = ['drivers']
|
||||||
|
|
||||||
|
# we don't receive context because we don't need db access at all
|
||||||
|
@classmethod
|
||||||
|
def get_object(cls, rule_type_name, **kwargs):
|
||||||
|
plugin = directory.get_plugin(alias=constants.QOS)
|
||||||
|
drivers = plugin.supported_rule_type_details(rule_type_name)
|
||||||
|
drivers_obj = [QosRuleTypeDriver(
|
||||||
|
name=driver['name'],
|
||||||
|
supported_parameters=driver['supported_parameters'])
|
||||||
|
for driver in drivers]
|
||||||
|
|
||||||
|
return cls(type=rule_type_name, drivers=drivers_obj)
|
||||||
|
|
||||||
# we don't receive context because we don't need db access at all
|
# we don't receive context because we don't need db access at all
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_objects(cls, validate_filters=True, **kwargs):
|
def get_objects(cls, validate_filters=True, **kwargs):
|
||||||
@ -52,3 +71,29 @@ class QosRuleType(base.NeutronObject):
|
|||||||
|
|
||||||
# TODO(ihrachys): apply filters to returned result
|
# TODO(ihrachys): apply filters to returned result
|
||||||
return [cls(type=type_) for type_ in rule_types]
|
return [cls(type=type_) for type_ in rule_types]
|
||||||
|
|
||||||
|
def obj_make_compatible(self, primitive, target_version):
|
||||||
|
_target_version = versionutils.convert_version_to_tuple(target_version)
|
||||||
|
|
||||||
|
if _target_version < (1, 3):
|
||||||
|
primitive.pop('drivers', None)
|
||||||
|
|
||||||
|
|
||||||
|
@obj_base.VersionedObjectRegistry.register
|
||||||
|
class QosRuleTypeDriver(base.NeutronObject):
|
||||||
|
# Version 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'name': obj_fields.StringField(),
|
||||||
|
'supported_parameters': common_types.ListOfDictOfMiscValuesField()
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'name': self.name,
|
||||||
|
'supported_parameters': self.supported_parameters}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_objects(cls, context, **kwargs):
|
||||||
|
raise NotImplementedError()
|
||||||
|
@ -20,6 +20,7 @@ from neutron.api.rpc.callbacks import events as rpc_events
|
|||||||
from neutron.api.rpc.callbacks.producer import registry as rpc_registry
|
from neutron.api.rpc.callbacks.producer import registry as rpc_registry
|
||||||
from neutron.api.rpc.callbacks import resources
|
from neutron.api.rpc.callbacks import resources
|
||||||
from neutron.api.rpc.handlers import resources_rpc
|
from neutron.api.rpc.handlers import resources_rpc
|
||||||
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.objects.qos import policy as policy_object
|
from neutron.objects.qos import policy as policy_object
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
@ -83,6 +84,20 @@ class QosServiceDriverManager(object):
|
|||||||
'driver': driver.name})
|
'driver': driver.name})
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_parameter_values(parameter_values):
|
||||||
|
validator, possible_values = list(parameter_values.items())[0]
|
||||||
|
if validator == 'type:range':
|
||||||
|
parameter_values = {
|
||||||
|
"start": possible_values[0],
|
||||||
|
"end": possible_values[1]
|
||||||
|
}
|
||||||
|
parameter_type = constants.VALUES_TYPE_RANGE
|
||||||
|
elif validator == 'type:values':
|
||||||
|
parameter_values = possible_values
|
||||||
|
parameter_type = constants.VALUES_TYPE_CHOICES
|
||||||
|
return parameter_values, parameter_type
|
||||||
|
|
||||||
def call(self, method_name, *args, **kwargs):
|
def call(self, method_name, *args, **kwargs):
|
||||||
"""Helper method for calling a method across all extension drivers."""
|
"""Helper method for calling a method across all extension drivers."""
|
||||||
exc_list = []
|
exc_list = []
|
||||||
@ -158,3 +173,27 @@ class QosServiceDriverManager(object):
|
|||||||
LOG.debug("Supported QoS rule types "
|
LOG.debug("Supported QoS rule types "
|
||||||
"(common subset for all loaded QoS drivers): %s", rule_types)
|
"(common subset for all loaded QoS drivers): %s", rule_types)
|
||||||
return rule_types
|
return rule_types
|
||||||
|
|
||||||
|
def supported_rule_type_details(self, rule_type_name):
|
||||||
|
if not self._drivers:
|
||||||
|
return []
|
||||||
|
|
||||||
|
rule_type_drivers = []
|
||||||
|
for driver in self._drivers:
|
||||||
|
if rule_type_name in driver.supported_rules:
|
||||||
|
supported_parameters = []
|
||||||
|
rule_parameters = driver.supported_rules.get(rule_type_name)
|
||||||
|
for name, values in rule_parameters.items():
|
||||||
|
parameter_values, parameter_type = (
|
||||||
|
self._parse_parameter_values(values))
|
||||||
|
supported_parameters.append({
|
||||||
|
"parameter_name": name,
|
||||||
|
"parameter_values": parameter_values,
|
||||||
|
"parameter_type": parameter_type
|
||||||
|
})
|
||||||
|
rule_type_drivers.append({
|
||||||
|
"name": driver.name,
|
||||||
|
"supported_parameters": supported_parameters
|
||||||
|
})
|
||||||
|
|
||||||
|
return rule_type_drivers
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
from neutron_lib.callbacks import events as callbacks_events
|
from neutron_lib.callbacks import events as callbacks_events
|
||||||
from neutron_lib.callbacks import registry as callbacks_registry
|
from neutron_lib.callbacks import registry as callbacks_registry
|
||||||
from neutron_lib.callbacks import resources as callbacks_resources
|
from neutron_lib.callbacks import resources as callbacks_resources
|
||||||
|
from neutron_lib import exceptions as lib_exc
|
||||||
|
|
||||||
from neutron.common import exceptions as n_exc
|
from neutron.common import exceptions as n_exc
|
||||||
from neutron.db import api as db_api
|
from neutron.db import api as db_api
|
||||||
@ -40,7 +41,8 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
"""
|
"""
|
||||||
supported_extension_aliases = ['qos',
|
supported_extension_aliases = ['qos',
|
||||||
'qos-bw-limit-direction',
|
'qos-bw-limit-direction',
|
||||||
'qos-default']
|
'qos-default',
|
||||||
|
'qos-rule-type-details']
|
||||||
|
|
||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
@ -264,6 +266,13 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
return policy_object.QosPolicy.get_objects(context, _pager=pager,
|
return policy_object.QosPolicy.get_objects(context, _pager=pager,
|
||||||
**filters)
|
**filters)
|
||||||
|
|
||||||
|
@db_base_plugin_common.filter_fields
|
||||||
|
@db_base_plugin_common.convert_result_to_dict
|
||||||
|
def get_rule_type(self, context, rule_type_name, fields=None):
|
||||||
|
if not context.is_admin:
|
||||||
|
raise lib_exc.NotAuthorized()
|
||||||
|
return rule_type_object.QosRuleType.get_object(rule_type_name)
|
||||||
|
|
||||||
@db_base_plugin_common.filter_fields
|
@db_base_plugin_common.filter_fields
|
||||||
@db_base_plugin_common.convert_result_to_dict
|
@db_base_plugin_common.convert_result_to_dict
|
||||||
def get_rule_types(self, context, filters=None, fields=None,
|
def get_rule_types(self, context, filters=None, fields=None,
|
||||||
@ -273,6 +282,9 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
filters = {}
|
filters = {}
|
||||||
return rule_type_object.QosRuleType.get_objects(**filters)
|
return rule_type_object.QosRuleType.get_objects(**filters)
|
||||||
|
|
||||||
|
def supported_rule_type_details(self, rule_type_name):
|
||||||
|
return self.driver_manager.supported_rule_type_details(rule_type_name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_rule_types(self):
|
def supported_rule_types(self):
|
||||||
return self.driver_manager.supported_rule_types
|
return self.driver_manager.supported_rule_types
|
||||||
|
@ -31,6 +31,12 @@ class QosTestJSON(base.BaseAdminNetworkTest):
|
|||||||
|
|
||||||
required_extensions = ['qos']
|
required_extensions = ['qos']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_driver_details(rule_type_details, driver_name):
|
||||||
|
for driver in rule_type_details['drivers']:
|
||||||
|
if driver['name'] == driver_name:
|
||||||
|
return driver
|
||||||
|
|
||||||
@decorators.idempotent_id('108fbdf7-3463-4e47-9871-d07f3dcf5bbb')
|
@decorators.idempotent_id('108fbdf7-3463-4e47-9871-d07f3dcf5bbb')
|
||||||
def test_create_policy(self):
|
def test_create_policy(self):
|
||||||
policy = self.create_qos_policy(name='test-policy',
|
policy = self.create_qos_policy(name='test-policy',
|
||||||
@ -172,6 +178,31 @@ class QosTestJSON(base.BaseAdminNetworkTest):
|
|||||||
for rule in actual_list_rule_types:
|
for rule in actual_list_rule_types:
|
||||||
self.assertEqual(tuple(expected_rule_keys), tuple(rule.keys()))
|
self.assertEqual(tuple(expected_rule_keys), tuple(rule.keys()))
|
||||||
|
|
||||||
|
@decorators.idempotent_id('8ececa21-ef97-4904-a152-9f04c90f484d')
|
||||||
|
def test_show_rule_type_details_as_user(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.Forbidden,
|
||||||
|
self.client.show_qos_rule_type,
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('d0a2460b-7325-481f-a531-050bd96ab25e')
|
||||||
|
def test_show_rule_type_details_as_admin(self):
|
||||||
|
# Since returned rule types depend on loaded backend drivers this test
|
||||||
|
# is checking only if returned keys are same as expected keys
|
||||||
|
|
||||||
|
# In theory, we could make the test conditional on which ml2 drivers
|
||||||
|
# are enabled in gate, but that option doesn't seem to be
|
||||||
|
# available through tempest.lib framework
|
||||||
|
expected_rule_type_details_keys = ['type', 'drivers']
|
||||||
|
|
||||||
|
rule_type_details = self.admin_client.show_qos_rule_type(
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT).get("rule_type")
|
||||||
|
|
||||||
|
# Verify that only required fields present in rule details
|
||||||
|
self.assertEqual(
|
||||||
|
sorted(tuple(expected_rule_type_details_keys)),
|
||||||
|
sorted(tuple(rule_type_details.keys())))
|
||||||
|
|
||||||
def _disassociate_network(self, client, network_id):
|
def _disassociate_network(self, client, network_id):
|
||||||
updated_network = client.update_network(network_id,
|
updated_network = client.update_network(network_id,
|
||||||
qos_policy_id=None)
|
qos_policy_id=None)
|
||||||
|
@ -728,6 +728,14 @@ class NetworkClientJSON(service_client.RestClient):
|
|||||||
body = jsonutils.loads(body)
|
body = jsonutils.loads(body)
|
||||||
return service_client.ResponseBody(resp, body)
|
return service_client.ResponseBody(resp, body)
|
||||||
|
|
||||||
|
def show_qos_rule_type(self, rule_type_name):
|
||||||
|
uri = '%s/qos/rule-types/%s' % (
|
||||||
|
self.uri_prefix, rule_type_name)
|
||||||
|
resp, body = self.get(uri)
|
||||||
|
self.expected_success(200, resp.status)
|
||||||
|
body = jsonutils.loads(body)
|
||||||
|
return service_client.ResponseBody(resp, body)
|
||||||
|
|
||||||
def create_trunk(self, parent_port_id, subports,
|
def create_trunk(self, parent_port_id, subports,
|
||||||
tenant_id=None, name=None, admin_state_up=None,
|
tenant_id=None, name=None, admin_state_up=None,
|
||||||
description=None):
|
description=None):
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from neutron.common import constants
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.objects.qos import rule_type
|
from neutron.objects.qos import rule_type
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
@ -25,6 +26,22 @@ from neutron.tests import base as test_base
|
|||||||
|
|
||||||
DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
|
DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
|
||||||
|
|
||||||
|
DRIVER_SUPPORTED_PARAMETERS = [
|
||||||
|
{
|
||||||
|
'parameter_name': qos_consts.MAX_KBPS,
|
||||||
|
'parameter_type': constants.VALUES_TYPE_RANGE,
|
||||||
|
'parameter_values': {"start": 0, "end": constants.DB_INTEGER_MAX_VALUE}
|
||||||
|
}, {
|
||||||
|
'parameter_name': qos_consts.MAX_BURST,
|
||||||
|
'parameter_type': constants.VALUES_TYPE_RANGE,
|
||||||
|
'parameter_values': {"start": 0, "end": constants.DB_INTEGER_MAX_VALUE}
|
||||||
|
}, {
|
||||||
|
'parameter_name': qos_consts.DIRECTION,
|
||||||
|
'parameter_type': constants.VALUES_TYPE_CHOICES,
|
||||||
|
'parameter_values': constants.VALID_DIRECTIONS
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
|
class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
|
||||||
|
|
||||||
@ -37,6 +54,26 @@ class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
|
|||||||
cfg.CONF.set_override("service_plugins", ["qos"])
|
cfg.CONF.set_override("service_plugins", ["qos"])
|
||||||
manager.init()
|
manager.init()
|
||||||
|
|
||||||
|
def test_get_object(self):
|
||||||
|
driver_details = {
|
||||||
|
'name': "backend_driver",
|
||||||
|
'supported_parameters': DRIVER_SUPPORTED_PARAMETERS
|
||||||
|
}
|
||||||
|
with mock.patch.object(
|
||||||
|
qos_plugin.QoSPlugin, 'supported_rule_type_details',
|
||||||
|
return_value=[driver_details]
|
||||||
|
):
|
||||||
|
rule_type_details = rule_type.QosRuleType.get_object(
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
|
||||||
|
self.assertEqual(
|
||||||
|
driver_details['name'], rule_type_details.drivers[0].name)
|
||||||
|
self.assertEqual(
|
||||||
|
driver_details['supported_parameters'],
|
||||||
|
rule_type_details.drivers[0].supported_parameters)
|
||||||
|
self.assertEqual(1, len(rule_type_details.drivers))
|
||||||
|
self.assertEqual(
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT, rule_type_details.type)
|
||||||
|
|
||||||
def test_get_objects(self):
|
def test_get_objects(self):
|
||||||
rule_types_mock = mock.PropertyMock(
|
rule_types_mock = mock.PropertyMock(
|
||||||
return_value=set(qos_consts.VALID_RULE_TYPES))
|
return_value=set(qos_consts.VALID_RULE_TYPES))
|
||||||
@ -64,3 +101,14 @@ class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
|
|||||||
self.assertIn(qos_consts.RULE_TYPE_DSCP_MARKING,
|
self.assertIn(qos_consts.RULE_TYPE_DSCP_MARKING,
|
||||||
tuple(rule_type_v1_1.fields['type'].AUTO_TYPE.
|
tuple(rule_type_v1_1.fields['type'].AUTO_TYPE.
|
||||||
_valid_values))
|
_valid_values))
|
||||||
|
|
||||||
|
def test_object_version_degradation_1_3_to_1_2(self):
|
||||||
|
drivers_obj = rule_type.QosRuleTypeDriver(
|
||||||
|
name="backend_driver", supported_parameters=[{}]
|
||||||
|
)
|
||||||
|
qos_rule_type = rule_type.QosRuleType(
|
||||||
|
type=qos_consts.RULE_TYPE_BANDWIDTH_LIMIT, drivers=[drivers_obj])
|
||||||
|
|
||||||
|
rule_type_v1_2 = self._policy_through_version(qos_rule_type, '1.2')
|
||||||
|
self.assertNotIn("drivers", rule_type_v1_2)
|
||||||
|
self.assertIn("type", rule_type_v1_2)
|
||||||
|
@ -66,7 +66,8 @@ object_data = {
|
|||||||
'QosBandwidthLimitRule': '1.3-51b662b12a8d1dfa89288d826c6d26d3',
|
'QosBandwidthLimitRule': '1.3-51b662b12a8d1dfa89288d826c6d26d3',
|
||||||
'QosDscpMarkingRule': '1.3-0313c6554b34fd10c753cb63d638256c',
|
'QosDscpMarkingRule': '1.3-0313c6554b34fd10c753cb63d638256c',
|
||||||
'QosMinimumBandwidthRule': '1.3-314c3419f4799067cc31cc319080adff',
|
'QosMinimumBandwidthRule': '1.3-314c3419f4799067cc31cc319080adff',
|
||||||
'QosRuleType': '1.2-e6fd08fcca152c339cbd5e9b94b1b8e7',
|
'QosRuleType': '1.3-7286188edeb3a0386f9cf7979b9700fc',
|
||||||
|
'QosRuleTypeDriver': '1.0-7d8cb9f0ef661ac03700eae97118e3db',
|
||||||
'QosPolicy': '1.6-4adb0cde3102c10d8970ec9487fd7fe7',
|
'QosPolicy': '1.6-4adb0cde3102c10d8970ec9487fd7fe7',
|
||||||
'QosPolicyDefault': '1.0-59e5060eedb1f06dd0935a244d27d11c',
|
'QosPolicyDefault': '1.0-59e5060eedb1f06dd0935a244d27d11c',
|
||||||
'QosPolicyNetworkBinding': '1.0-df53a1e0f675aab8d27a1ccfed38dc42',
|
'QosPolicyNetworkBinding': '1.0-df53a1e0f675aab8d27a1ccfed38dc42',
|
||||||
|
@ -206,6 +206,89 @@ class TestQosDriversManagerRules(TestQosDriversManagerBase):
|
|||||||
})
|
})
|
||||||
self.assertEqual(driver_manager.supported_rule_types, set([]))
|
self.assertEqual(driver_manager.supported_rule_types, set([]))
|
||||||
|
|
||||||
|
def test__parse_parameter_values(self):
|
||||||
|
range_parameter = {'type:range': [0, 10]}
|
||||||
|
values_parameter = {'type:values': [1, 10, 100, 1000]}
|
||||||
|
expected_parsed_range_parameter = {'start': 0, 'end': 10}
|
||||||
|
expected_parsed_values_parameter = [1, 10, 100, 1000]
|
||||||
|
|
||||||
|
parameter_values, parameter_type = (
|
||||||
|
driver_mgr.QosServiceDriverManager._parse_parameter_values(
|
||||||
|
range_parameter))
|
||||||
|
self.assertEqual(
|
||||||
|
expected_parsed_range_parameter, parameter_values)
|
||||||
|
self.assertEqual(
|
||||||
|
constants.VALUES_TYPE_RANGE, parameter_type)
|
||||||
|
|
||||||
|
parameter_values, parameter_type = (
|
||||||
|
driver_mgr.QosServiceDriverManager._parse_parameter_values(
|
||||||
|
values_parameter))
|
||||||
|
self.assertEqual(
|
||||||
|
expected_parsed_values_parameter, parameter_values)
|
||||||
|
self.assertEqual(
|
||||||
|
constants.VALUES_TYPE_CHOICES, parameter_type)
|
||||||
|
|
||||||
|
def test_supported_rule_type_details(self):
|
||||||
|
driver_manager = self._create_manager_with_drivers({
|
||||||
|
'driver-A': {
|
||||||
|
'is_loaded': True,
|
||||||
|
'rules': {
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: {
|
||||||
|
"max_kbps": {'type:range': [0, 1000]},
|
||||||
|
"max_burst_kbps": {'type:range': [0, 1000]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'driver-B': {
|
||||||
|
'is_loaded': True,
|
||||||
|
'rules': {
|
||||||
|
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: {
|
||||||
|
"min_kbps": {'type:range': [0, 1000]},
|
||||||
|
'direction': {
|
||||||
|
'type:values': constants.VALID_DIRECTIONS}
|
||||||
|
},
|
||||||
|
qos_consts.RULE_TYPE_DSCP_MARKING: {
|
||||||
|
"dscp_mark": {
|
||||||
|
'type:values': constants.VALID_DSCP_MARKS}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expected_rule_type_details = [{
|
||||||
|
'name': 'driver-A',
|
||||||
|
'supported_parameters': [{
|
||||||
|
'parameter_name': 'max_kbps',
|
||||||
|
'parameter_type': constants.VALUES_TYPE_RANGE,
|
||||||
|
'parameter_values': {'start': 0, 'end': 1000}
|
||||||
|
}, {
|
||||||
|
'parameter_name': 'max_burst_kbps',
|
||||||
|
'parameter_type': constants.VALUES_TYPE_RANGE,
|
||||||
|
'parameter_values': {'start': 0, 'end': 1000}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
bandwidth_limit_details = driver_manager.supported_rule_type_details(
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
|
||||||
|
self.assertEqual(
|
||||||
|
len(expected_rule_type_details), len(bandwidth_limit_details))
|
||||||
|
self.assertEqual(
|
||||||
|
expected_rule_type_details[0]['name'],
|
||||||
|
bandwidth_limit_details[0]['name'])
|
||||||
|
self.assertEqual(
|
||||||
|
len(expected_rule_type_details[0]['supported_parameters']),
|
||||||
|
len(bandwidth_limit_details[0]['supported_parameters'])
|
||||||
|
)
|
||||||
|
for parameter in expected_rule_type_details[0]['supported_parameters']:
|
||||||
|
self.assertIn(
|
||||||
|
parameter,
|
||||||
|
bandwidth_limit_details[0]['supported_parameters'])
|
||||||
|
|
||||||
|
def test_supported_rule_type_details_no_drivers_loaded(self):
|
||||||
|
driver_manager = self._create_manager_with_drivers({})
|
||||||
|
self.assertEqual(
|
||||||
|
[],
|
||||||
|
driver_manager.supported_rule_type_details(
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT))
|
||||||
|
|
||||||
|
|
||||||
class TestQosDriversCalls(TestQosDriversManagerBase):
|
class TestQosDriversCalls(TestQosDriversManagerBase):
|
||||||
"""Test QoS driver calls"""
|
"""Test QoS driver calls"""
|
||||||
|
@ -12,16 +12,18 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from neutron_lib import context
|
from neutron_lib import context
|
||||||
|
from neutron_lib import exceptions as lib_exc
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions as n_exc
|
from neutron.common import exceptions as n_exc
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.objects import base as base_object
|
from neutron.objects import base as base_object
|
||||||
from neutron.objects.qos import policy as policy_object
|
from neutron.objects.qos import policy as policy_object
|
||||||
from neutron.objects.qos import rule as rule_object
|
from neutron.objects.qos import rule as rule_object
|
||||||
from neutron.plugins.common import constants
|
from neutron.plugins.common import constants as plugins_constants
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
from neutron.services.qos import qos_plugin
|
from neutron.services.qos import qos_plugin
|
||||||
from neutron.tests.unit.services.qos import base
|
from neutron.tests.unit.services.qos import base
|
||||||
@ -55,7 +57,7 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
cfg.CONF.set_override("service_plugins", ["qos"])
|
cfg.CONF.set_override("service_plugins", ["qos"])
|
||||||
|
|
||||||
manager.init()
|
manager.init()
|
||||||
self.qos_plugin = directory.get_plugin(constants.QOS)
|
self.qos_plugin = directory.get_plugin(plugins_constants.QOS)
|
||||||
|
|
||||||
self.qos_plugin.driver_manager = mock.Mock()
|
self.qos_plugin.driver_manager = mock.Mock()
|
||||||
|
|
||||||
@ -811,6 +813,34 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
self.assertRaises(AttributeError, getattr, self.qos_plugin,
|
self.assertRaises(AttributeError, getattr, self.qos_plugin,
|
||||||
'create_policy_bandwidth_limit_rules')
|
'create_policy_bandwidth_limit_rules')
|
||||||
|
|
||||||
|
def test_get_rule_type(self):
|
||||||
|
admin_ctxt = context.get_admin_context()
|
||||||
|
drivers_details = [{
|
||||||
|
'name': 'fake-driver',
|
||||||
|
'supported_parameters': [{
|
||||||
|
'parameter_name': 'max_kbps',
|
||||||
|
'parameter_type': 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_consts.RULE_TYPE_BANDWIDTH_LIMIT)
|
||||||
|
self.assertEqual(
|
||||||
|
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||||
|
rule_type_details['type'])
|
||||||
|
self.assertEqual(
|
||||||
|
drivers_details, rule_type_details['drivers'])
|
||||||
|
|
||||||
|
def test_get_rule_type_as_user(self):
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.NotAuthorized,
|
||||||
|
self.qos_plugin.get_rule_type,
|
||||||
|
self.ctxt, qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
|
||||||
|
|
||||||
def test_get_rule_types(self):
|
def test_get_rule_types(self):
|
||||||
rule_types_mock = mock.PropertyMock(
|
rule_types_mock = mock.PropertyMock(
|
||||||
return_value=qos_consts.VALID_RULE_TYPES)
|
return_value=qos_consts.VALID_RULE_TYPES)
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
New API to get details of supported rule types.
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The QoS service plugin can now expose details about supported QoS rule
|
||||||
|
types in Neutron deployment.
|
||||||
|
New API call is allowed only for users with admin priviliges.
|
Loading…
x
Reference in New Issue
Block a user