From da736d115bfeb10c9adf8d019696203bba5cbf8d Mon Sep 17 00:00:00 2001 From: Hongbin Lu Date: Sun, 1 Oct 2017 17:53:50 +0000 Subject: [PATCH] Allow multiple binding drivers In before, only one binding driver is allowed. This patch introduces a new config to support multiple binding drivers. The first use case is to allow SR-IOV binding to be co-existed with other binding. * Rename the config 'driver' to 'default_driver' in 'binding' group. This is for making it clear that it is allowed to have more than one type of bindings. * Introduce a new config called 'enabled_drivers'. * Allow client to pass a driver name to port_bind and port_unbind. If this parameter is None, kuryr will load the default driver. Partial-Implements: blueprint sriov-binding Change-Id: I14b23379de9f2459ba97d5d82dfdb51553370cb1 --- kuryr/lib/binding/__init__.py | 27 +++++++++++++--- kuryr/lib/config.py | 6 +++- kuryr/lib/exceptions.py | 8 +++++ .../lib/segmentation_type_drivers/__init__.py | 2 +- kuryr/tests/unit/binding/__init__.py | 32 +++++++++++++++++++ .../segmentation_type_drivers/test_vlan.py | 2 +- kuryr/tests/unit/test_config.py | 2 +- ...tiple-binding-driver-512a6a7f620c758e.yaml | 11 +++++++ 8 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 releasenotes/notes/multiple-binding-driver-512a6a7f620c758e.yaml diff --git a/kuryr/lib/binding/__init__.py b/kuryr/lib/binding/__init__.py index 6834ef1f..734f026b 100644 --- a/kuryr/lib/binding/__init__.py +++ b/kuryr/lib/binding/__init__.py @@ -12,9 +12,17 @@ from oslo_config import cfg from oslo_utils import importutils +from kuryr.lib import exceptions + + +def _verify_driver(driver): + if driver.__name__ not in cfg.CONF.binding.enabled_drivers: + raise exceptions.DriverNotEnabledException( + 'Driver %s is not enabled' % driver.__name__) + def port_bind(endpoint_id, port, subnets, network=None, vm_port=None, - segmentation_id=None, **kwargs): + segmentation_id=None, driver=None, **kwargs): """Binds the Neutron port to the network interface on the host. :param endpoint_id: the ID of the endpoint as string @@ -29,30 +37,39 @@ def port_bind(endpoint_id, port, subnets, network=None, vm_port=None, port of a container which is running inside this Nova instance (either ipvlan/macvlan or a subport). :param segmentation_id: ID of the segment for container traffic isolation) + :param driver: the binding driver name :param kwargs: Additional driver-specific arguments :returns: the tuple of the names of the veth pair and the tuple of stdout and stderr returned by processutils.execute invoked with the executable script for binding :raises: kuryr.common.exceptions.VethCreationFailure, + kuryr.common.exceptions.DriverNotEnabledException, processutils.ProcessExecutionError """ - driver = importutils.import_module(cfg.CONF.binding.driver) + driver = importutils.import_module( + driver or cfg.CONF.binding.default_driver) + _verify_driver(driver) + return driver.port_bind(endpoint_id, port, subnets, network=network, vm_port=vm_port, segmentation_id=segmentation_id, **kwargs) -def port_unbind(endpoint_id, neutron_port, **kwargs): +def port_unbind(endpoint_id, neutron_port, driver=None, **kwargs): """Unbinds the Neutron port from the network interface on the host. :param endpoint_id: the ID of the Docker container as string :param neutron_port: a port dictionary returned from python-neutronclient + :param driver: the binding driver name :param kwargs: Additional driver-specific arguments :returns: the tuple of stdout and stderr returned by processutils.execute invoked with the executable script for unbinding - :raises: processutils.ProcessExecutionError, pyroute2.NetlinkError + :raises: processutils.ProcessExecutionError, pyroute2.NetlinkError, + kuryr.common.exceptions.DriverNotEnabledException, """ - driver = importutils.import_module(cfg.CONF.binding.driver) + driver = importutils.import_module( + driver or cfg.CONF.binding.default_driver) + _verify_driver(driver) return driver.port_unbind(endpoint_id, neutron_port, **kwargs) diff --git a/kuryr/lib/config.py b/kuryr/lib/config.py index 413eb29a..6e65558d 100644 --- a/kuryr/lib/config.py +++ b/kuryr/lib/config.py @@ -68,9 +68,13 @@ binding_opts = [ default='eth', help=_('The name prefix of the veth endpoint put inside the ' 'container.')), - cfg.StrOpt('driver', + cfg.StrOpt('default_driver', default='kuryr.lib.binding.drivers.veth', + deprecated_name='driver', help=_('Driver to use for binding and unbinding ports.')), + cfg.ListOpt('enabled_drivers', + default=['kuryr.lib.binding.drivers.veth'], + help=_('Drivers to use for binding and unbinding ports.')), cfg.StrOpt('link_iface', default='', help=_('Specifies the name of the Nova instance interface to ' diff --git a/kuryr/lib/exceptions.py b/kuryr/lib/exceptions.py index 60fbccd5..e5042419 100644 --- a/kuryr/lib/exceptions.py +++ b/kuryr/lib/exceptions.py @@ -118,3 +118,11 @@ class AddressInUseException(KuryrException): This exception is thrown when a specific address is requested and the requested ip address already exists and is used. """ + + +class DriverNotEnabledException(KuryrException): + """Exception represents the binding driver is not enabled. + + This exception is thrown when kuryr tries to load a specific binding driver + but the driver is not enabled. + """ diff --git a/kuryr/lib/segmentation_type_drivers/__init__.py b/kuryr/lib/segmentation_type_drivers/__init__.py index ddef6a95..516beb82 100644 --- a/kuryr/lib/segmentation_type_drivers/__init__.py +++ b/kuryr/lib/segmentation_type_drivers/__init__.py @@ -22,7 +22,7 @@ _driver = "" def _get_driver(): global _driver if not _driver: - driver_name = cfg.CONF.binding.driver.rsplit('.', 1)[1] + driver_name = cfg.CONF.binding.default_driver.rsplit('.', 1)[1] # REVISIT(vikasc): Need to remove this if check if driver_name == 'vlan': diff --git a/kuryr/tests/unit/binding/__init__.py b/kuryr/tests/unit/binding/__init__.py index e69de29b..e6db7aa3 100644 --- a/kuryr/tests/unit/binding/__init__.py +++ b/kuryr/tests/unit/binding/__init__.py @@ -0,0 +1,32 @@ +# 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_config import cfg +from oslo_utils import importutils + +from kuryr.lib import binding +from kuryr.lib import exceptions +from kuryr.tests.unit import base + + +class TestBinding(base.TestCase): + """Unit tests for binding module""" + + def test__verify_driver(self): + cfg.CONF.set_override('enabled_drivers', + ['kuryr.lib.binding.drivers.veth'], + group='binding') + driver = importutils.import_module('kuryr.lib.binding.drivers.veth') + binding._verify_driver(driver) # assert no exception raise + driver = importutils.import_module('kuryr.lib.binding.drivers.vlan') + self.assertRaises(exceptions.DriverNotEnabledException, + binding._verify_driver, driver) diff --git a/kuryr/tests/unit/segmentation_type_drivers/test_vlan.py b/kuryr/tests/unit/segmentation_type_drivers/test_vlan.py index 15f0123b..47f7fdff 100644 --- a/kuryr/tests/unit/segmentation_type_drivers/test_vlan.py +++ b/kuryr/tests/unit/segmentation_type_drivers/test_vlan.py @@ -29,7 +29,7 @@ class VlanSegmentationDriverTest(base.TestCase): def setUp(self): super(VlanSegmentationDriverTest, self).setUp() - cfg.CONF.binding.driver = 'kuryr.lib.binding.drivers.vlan' + cfg.CONF.binding.default_driver = 'kuryr.lib.binding.drivers.vlan' def test_allocate_segmentation_id(self): vlan_seg_driver = vlan.SegmentationDriver() diff --git a/kuryr/tests/unit/test_config.py b/kuryr/tests/unit/test_config.py index 90cf118a..9bf4efb3 100644 --- a/kuryr/tests/unit/test_config.py +++ b/kuryr/tests/unit/test_config.py @@ -30,4 +30,4 @@ class ConfigurationTest(base.TestCase): self.assertEqual('baremetal', cfg.CONF.deployment_type) self.assertEqual('kuryr.lib.binding.drivers.veth', - cfg.CONF.binding.driver) + cfg.CONF.binding.default_driver) diff --git a/releasenotes/notes/multiple-binding-driver-512a6a7f620c758e.yaml b/releasenotes/notes/multiple-binding-driver-512a6a7f620c758e.yaml new file mode 100644 index 00000000..e669e515 --- /dev/null +++ b/releasenotes/notes/multiple-binding-driver-512a6a7f620c758e.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + Add support for multiple binding drivers. Introduce a new config + called 'enabled_drivers' which specifies a list of binding drivers + allowed to use. +deprecations: + - | + Rename the config 'driver' to 'default_driver' in 'binding' group. + This is for making it clear that it is allowed to have more than + one type of bindings.