diff --git a/neutron_lib/services/qos/__init__.py b/neutron_lib/services/qos/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron_lib/services/qos/base.py b/neutron_lib/services/qos/base.py new file mode 100644 index 000000000..4534a82da --- /dev/null +++ b/neutron_lib/services/qos/base.py @@ -0,0 +1,162 @@ +# Copyright 2016 Hewlett Packard Enterprise Development Company, LP +# Copyright 2016 Red Hat Inc. +# +# 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 oslo_log import log as logging + +from neutron_lib.api import validators as lib_validators +from neutron_lib.callbacks import events +from neutron_lib.callbacks import registry +from neutron_lib.services.qos import constants + +LOG = logging.getLogger(__name__) + + +@registry.has_registry_receivers +class DriverBase(object): + + def __init__(self, name, vif_types, vnic_types, + supported_rules, + requires_rpc_notifications=False): + """Instantiate a qos driver. + + :param name: driver name. + :param vif_types: list of interfaces (VIFs) supported. + :param vnic_types: list of vnic types supported. + :param supported_rules: dict of supported rules. + :param requires_rpc_notifications: indicates if this driver + expects rpc push notifications to be sent from the driver. + """ + + self.name = name + self.vif_types = vif_types + self.vnic_types = vnic_types + self.supported_rules = supported_rules + self.requires_rpc_notifications = requires_rpc_notifications + + @registry.receives(constants.QOS_PLUGIN, [events.AFTER_INIT]) + def _register(self, resource, event, trigger, **kwargs): + if self.is_loaded: + # trigger is the QosServiceDriverManager + trigger.register_driver(self) + + def is_loaded(self): + """True if the driver is active for the Neutron Server. + + Implement this property to determine if your driver is actively + configured for this Neutron Server deployment. + """ + return True + + def is_vif_type_compatible(self, vif_type): + """True if the driver is compatible with the VIF type.""" + return vif_type in self.vif_types + + def is_vnic_compatible(self, vnic_type): + """True if the driver is compatible with the specific VNIC type.""" + return vnic_type in self.vnic_types + + def is_rule_supported(self, rule): + supported_parameters = self.supported_rules.get(rule.rule_type) + if not supported_parameters: + LOG.debug("Rule type %(rule_type)s is not supported by " + "%(driver_name)s", + {'rule_type': rule.rule_type, + 'driver_name': self.name}) + return False + for parameter, validators in supported_parameters.items(): + parameter_value = rule.get(parameter) + for validator_type, validator_data in validators.items(): + validator_function = lib_validators.get_validator( + validator_type) + validate_result = validator_function(parameter_value, + validator_data) + # NOTE(slaweq): validator functions returns None if data is + # valid or string with reason why data is not valid + if validate_result: + LOG.debug("Parameter %(parameter)s=%(value)s in " + "rule type %(rule_type)s is not " + "supported by %(driver_name)s. " + "Validate result: %(validate_result)s", + {'parameter': parameter, + 'value': parameter_value, + 'rule_type': rule.rule_type, + 'driver_name': self.name, + 'validate_result': validate_result}) + return False + return True + + def create_policy(self, context, policy): + """Create policy invocation. + + This method can be implemented by the specific driver subclass + to update the backend where necessary with the specific policy + information. + + :param context: current running context information + :param policy: a QoSPolicy object being created, which will have no + rules. + """ + + def create_policy_precommit(self, context, policy): + """Create policy precommit. + + This method can be implemented by the specific driver subclass + to handle the precommit event of a policy that is being created. + + :param context: current running context information + :param policy: a QoSPolicy object being created, which will have no + rules. + """ + + def update_policy(self, context, policy): + """Update policy invocation. + + This method can be implemented by the specific driver subclass + to update the backend where necessary. + + :param context: current running context information + :param policy: a QoSPolicy object being updated. + """ + + def update_policy_precommit(self, context, policy): + """Update policy precommit. + + This method can be implemented by the specific driver subclass + to handle update precommit event of a policy that is being updated. + + :param context: current running context information + :param policy: a QoSPolicy object being updated. + """ + + def delete_policy(self, context, policy): + """Delete policy invocation. + + This method can be implemented by the specific driver subclass + to delete the backend policy where necessary. + + :param context: current running context information + :param policy: a QoSPolicy object being deleted + """ + + def delete_policy_precommit(self, context, policy): + """Delete policy precommit. + + This method can be implemented by the specific driver subclass + to handle delete precommit event of a policy that is being deleted. + + :param context: current running context information + :param policy: a QoSPolicy object being deleted + """ diff --git a/neutron_lib/services/qos/constants.py b/neutron_lib/services/qos/constants.py new file mode 100644 index 000000000..e4a14cf1b --- /dev/null +++ b/neutron_lib/services/qos/constants.py @@ -0,0 +1,56 @@ +# Copyright (c) 2015 Red Hat Inc. +# 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. + +RULE_TYPE_BANDWIDTH_LIMIT = 'bandwidth_limit' +RULE_TYPE_DSCP_MARKING = 'dscp_marking' +RULE_TYPE_MINIMUM_BANDWIDTH = 'minimum_bandwidth' +VALID_RULE_TYPES = [RULE_TYPE_BANDWIDTH_LIMIT, + RULE_TYPE_DSCP_MARKING, + RULE_TYPE_MINIMUM_BANDWIDTH, + ] + +# Names of rules' attributes +MAX_KBPS = "max_kbps" +MAX_BURST = "max_burst_kbps" +MIN_KBPS = "min_kbps" +DIRECTION = "direction" +DSCP_MARK = "dscp_mark" + +QOS_POLICY_ID = 'qos_policy_id' + +QOS_PLUGIN = 'qos_plugin' + +# NOTE(slaweq): Value used to calculate burst value for egress bandwidth limit +# if burst is not given by user. In such case burst value will be calculated +# as 80% of bw_limit to ensure that at least limits for TCP traffic will work +# fine. +DEFAULT_BURST_RATE = 0.8 + +# Method names for QoSDriver +PRECOMMIT_POSTFIX = '_precommit' +CREATE_POLICY = 'create_policy' +CREATE_POLICY_PRECOMMIT = CREATE_POLICY + PRECOMMIT_POSTFIX +UPDATE_POLICY = 'update_policy' +UPDATE_POLICY_PRECOMMIT = UPDATE_POLICY + PRECOMMIT_POSTFIX +DELETE_POLICY = 'delete_policy' +DELETE_POLICY_PRECOMMIT = DELETE_POLICY + PRECOMMIT_POSTFIX + +QOS_CALL_METHODS = ( + CREATE_POLICY, + CREATE_POLICY_PRECOMMIT, + UPDATE_POLICY, + UPDATE_POLICY_PRECOMMIT, + DELETE_POLICY, + DELETE_POLICY_PRECOMMIT, ) diff --git a/neutron_lib/tests/unit/services/qos/__init__.py b/neutron_lib/tests/unit/services/qos/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron_lib/tests/unit/services/qos/test_base.py b/neutron_lib/tests/unit/services/qos/test_base.py new file mode 100644 index 000000000..82e9e5cb9 --- /dev/null +++ b/neutron_lib/tests/unit/services/qos/test_base.py @@ -0,0 +1,81 @@ +# 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. + +import mock + +from neutron_lib.api.definitions import portbindings +from neutron_lib.services.qos import base as qos_base +from neutron_lib.services.qos import constants as qos_consts +from neutron_lib.tests import _base + + +SUPPORTED_RULES = { + qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: { + "min_kbps": {'type:values': None}, + 'direction': {'type:values': ['egress']} + } +} + + +def _make_rule(rule_type='fake-rule-type', params=None): + mock_rule = mock.MagicMock() + mock_rule.rule_type = rule_type + params = params or {} + mock_rule.get = params.get + return mock_rule + + +def _make_driver(name='fake-driver', + vif_types=[portbindings.VIF_TYPE_OVS], + vnic_types=[portbindings.VNIC_NORMAL], + supported_rules=SUPPORTED_RULES, + requires_rpc_notifications=False): + return qos_base.DriverBase( + name, vif_types, vnic_types, supported_rules, + requires_rpc_notifications=requires_rpc_notifications) + + +class TestDriverBase(_base.BaseTestCase): + + def test_is_loaded(self): + self.assertTrue(_make_driver().is_loaded()) + + def test_is_vif_type_compatible(self): + self.assertTrue( + _make_driver().is_vif_type_compatible( + portbindings.VIF_TYPE_OVS)) + self.assertFalse( + _make_driver().is_vif_type_compatible( + portbindings.VIF_TYPE_BRIDGE)) + + def test_is_vnic_compatible(self): + self.assertTrue( + _make_driver().is_vnic_compatible(portbindings.VNIC_NORMAL)) + self.assertFalse( + _make_driver().is_vnic_compatible(portbindings.VNIC_BAREMETAL)) + + def test_is_rule_supported_with_unsupported_rule(self): + self.assertFalse(_make_driver().is_rule_supported(_make_rule())) + + def test_is_rule_supported(self): + self.assertTrue( + _make_driver().is_rule_supported( + _make_rule( + rule_type=qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH, + params={'min_kbps': None, 'direction': 'egress'}))) + self.assertFalse( + _make_driver().is_rule_supported( + _make_rule( + rule_type=qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH, + params={'min_kbps': None, 'direction': 'ingress'}))) diff --git a/releasenotes/notes/rehome-qos-driverbase-f729875b2ad74ce0.yaml b/releasenotes/notes/rehome-qos-driverbase-f729875b2ad74ce0.yaml new file mode 100644 index 000000000..1bbf9b065 --- /dev/null +++ b/releasenotes/notes/rehome-qos-driverbase-f729875b2ad74ce0.yaml @@ -0,0 +1,6 @@ +--- +features: + - The ``DriverBase`` class from ``neutron.services.qos.drivers.base`` is now + available in the ``neutron_lib.services.qos.base`` module. + - The constants defined in ``neutron.services.qos.qos_consts`` are now + available in ``neutron_lib.services.qos.constants``.