rehome ml2 MechanismDriver class
The ML2 MechanismDriver from neutron is pluggable and widely used by sub-projects [1]. This patch proposes we rehome the class into neutron-lib to break this dependency. UTs and a release note are also included. [1] http://codesearch.openstack.org/?q=MechanismDriver Change-Id: Ia1459103a96e293a05f04b1db16c53673eb2e37c
This commit is contained in:
		
							
								
								
									
										0
									
								
								neutron_lib/plugins/ml2/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								neutron_lib/plugins/ml2/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										412
									
								
								neutron_lib/plugins/ml2/api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								neutron_lib/plugins/ml2/api.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,412 @@
 | 
			
		||||
# 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 abc
 | 
			
		||||
import six
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# The following keys are used in the segment dictionaries passed via
 | 
			
		||||
# the driver API.
 | 
			
		||||
ID = 'id'
 | 
			
		||||
NETWORK_TYPE = 'network_type'
 | 
			
		||||
PHYSICAL_NETWORK = 'physical_network'
 | 
			
		||||
SEGMENTATION_ID = 'segmentation_id'
 | 
			
		||||
MTU = 'mtu'
 | 
			
		||||
 | 
			
		||||
# The following keys are used in the binding level dictionaries
 | 
			
		||||
# available via the binding_levels and original_binding_levels
 | 
			
		||||
# PortContext properties.
 | 
			
		||||
BOUND_DRIVER = 'bound_driver'
 | 
			
		||||
BOUND_SEGMENT = 'bound_segment'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@six.add_metaclass(abc.ABCMeta)
 | 
			
		||||
class MechanismDriver(object):
 | 
			
		||||
    """Define stable abstract interface for ML2 mechanism drivers.
 | 
			
		||||
 | 
			
		||||
    A mechanism driver is called on the creation, update, and deletion
 | 
			
		||||
    of networks and ports. For every event, there are two methods that
 | 
			
		||||
    get called - one within the database transaction (method suffix of
 | 
			
		||||
    _precommit), one right afterwards (method suffix of _postcommit).
 | 
			
		||||
 | 
			
		||||
    Exceptions raised by methods called inside the transaction can
 | 
			
		||||
    rollback, but should not make any blocking calls (for example,
 | 
			
		||||
    REST requests to an outside controller). Methods called after
 | 
			
		||||
    transaction commits can make blocking external calls, though these
 | 
			
		||||
    will block the entire process. Exceptions raised in calls after
 | 
			
		||||
    the transaction commits may cause the associated resource to be
 | 
			
		||||
    deleted.
 | 
			
		||||
 | 
			
		||||
    Because rollback outside of the transaction is not done in the
 | 
			
		||||
    update network/port case, all data validation must be done within
 | 
			
		||||
    methods that are part of the database transaction.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def initialize(self):
 | 
			
		||||
        """Perform driver initialization.
 | 
			
		||||
 | 
			
		||||
        Called after all drivers have been loaded and the database has
 | 
			
		||||
        been initialized. No abstract methods defined below will be
 | 
			
		||||
        called prior to this method being called.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_network_precommit(self, context):
 | 
			
		||||
        """Allocate resources for a new network.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the new
 | 
			
		||||
        network.
 | 
			
		||||
 | 
			
		||||
        Create a new network, allocating resources as necessary in the
 | 
			
		||||
        database. Called inside transaction context on session. Call
 | 
			
		||||
        cannot block.  Raising an exception will result in a rollback
 | 
			
		||||
        of the current transaction.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_network_postcommit(self, context):
 | 
			
		||||
        """Create a network.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the new
 | 
			
		||||
        network.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction commits. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance. Raising an exception will
 | 
			
		||||
        cause the deletion of the resource.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def update_network_precommit(self, context):
 | 
			
		||||
        """Update resources of a network.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the new
 | 
			
		||||
        state of the network, as well as the original state prior
 | 
			
		||||
        to the update_network call.
 | 
			
		||||
 | 
			
		||||
        Update values of a network, updating the associated resources
 | 
			
		||||
        in the database. Called inside transaction context on session.
 | 
			
		||||
        Raising an exception will result in rollback of the
 | 
			
		||||
        transaction.
 | 
			
		||||
 | 
			
		||||
        update_network_precommit is called for all changes to the
 | 
			
		||||
        network state. It is up to the mechanism driver to ignore
 | 
			
		||||
        state or state changes that it does not know or care about.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def update_network_postcommit(self, context):
 | 
			
		||||
        """Update a network.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the new
 | 
			
		||||
        state of the network, as well as the original state prior
 | 
			
		||||
        to the update_network call.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction commits. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance. Raising an exception will
 | 
			
		||||
        cause the deletion of the resource.
 | 
			
		||||
 | 
			
		||||
        update_network_postcommit is called for all changes to the
 | 
			
		||||
        network state.  It is up to the mechanism driver to ignore
 | 
			
		||||
        state or state changes that it does not know or care about.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def delete_network_precommit(self, context):
 | 
			
		||||
        """Delete resources for a network.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the current
 | 
			
		||||
        state of the network, prior to the call to delete it.
 | 
			
		||||
 | 
			
		||||
        Delete network resources previously allocated by this
 | 
			
		||||
        mechanism driver for a network. Called inside transaction
 | 
			
		||||
        context on session. Runtime errors are not expected, but
 | 
			
		||||
        raising an exception will result in rollback of the
 | 
			
		||||
        transaction.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def delete_network_postcommit(self, context):
 | 
			
		||||
        """Delete a network.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the current
 | 
			
		||||
        state of the network, prior to the call to delete it.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction commits. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance. Runtime errors are not
 | 
			
		||||
        expected, and will not prevent the resource from being
 | 
			
		||||
        deleted.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_subnet_precommit(self, context):
 | 
			
		||||
        """Allocate resources for a new subnet.
 | 
			
		||||
 | 
			
		||||
        :param context: SubnetContext instance describing the new
 | 
			
		||||
        subnet.
 | 
			
		||||
 | 
			
		||||
        Create a new subnet, allocating resources as necessary in the
 | 
			
		||||
        database. Called inside transaction context on session. Call
 | 
			
		||||
        cannot block.  Raising an exception will result in a rollback
 | 
			
		||||
        of the current transaction.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_subnet_postcommit(self, context):
 | 
			
		||||
        """Create a subnet.
 | 
			
		||||
 | 
			
		||||
        :param context: SubnetContext instance describing the new
 | 
			
		||||
        subnet.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction commits. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance. Raising an exception will
 | 
			
		||||
        cause the deletion of the resource.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def update_subnet_precommit(self, context):
 | 
			
		||||
        """Update resources of a subnet.
 | 
			
		||||
 | 
			
		||||
        :param context: SubnetContext instance describing the new
 | 
			
		||||
        state of the subnet, as well as the original state prior
 | 
			
		||||
        to the update_subnet call.
 | 
			
		||||
 | 
			
		||||
        Update values of a subnet, updating the associated resources
 | 
			
		||||
        in the database. Called inside transaction context on session.
 | 
			
		||||
        Raising an exception will result in rollback of the
 | 
			
		||||
        transaction.
 | 
			
		||||
 | 
			
		||||
        update_subnet_precommit is called for all changes to the
 | 
			
		||||
        subnet state. It is up to the mechanism driver to ignore
 | 
			
		||||
        state or state changes that it does not know or care about.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def update_subnet_postcommit(self, context):
 | 
			
		||||
        """Update a subnet.
 | 
			
		||||
 | 
			
		||||
        :param context: SubnetContext instance describing the new
 | 
			
		||||
        state of the subnet, as well as the original state prior
 | 
			
		||||
        to the update_subnet call.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction commits. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance. Raising an exception will
 | 
			
		||||
        cause the deletion of the resource.
 | 
			
		||||
 | 
			
		||||
        update_subnet_postcommit is called for all changes to the
 | 
			
		||||
        subnet state.  It is up to the mechanism driver to ignore
 | 
			
		||||
        state or state changes that it does not know or care about.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def delete_subnet_precommit(self, context):
 | 
			
		||||
        """Delete resources for a subnet.
 | 
			
		||||
 | 
			
		||||
        :param context: SubnetContext instance describing the current
 | 
			
		||||
        state of the subnet, prior to the call to delete it.
 | 
			
		||||
 | 
			
		||||
        Delete subnet resources previously allocated by this
 | 
			
		||||
        mechanism driver for a subnet. Called inside transaction
 | 
			
		||||
        context on session. Runtime errors are not expected, but
 | 
			
		||||
        raising an exception will result in rollback of the
 | 
			
		||||
        transaction.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def delete_subnet_postcommit(self, context):
 | 
			
		||||
        """Delete a subnet.
 | 
			
		||||
 | 
			
		||||
        :param context: SubnetContext instance describing the current
 | 
			
		||||
        state of the subnet, prior to the call to delete it.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction commits. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance. Runtime errors are not
 | 
			
		||||
        expected, and will not prevent the resource from being
 | 
			
		||||
        deleted.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_port_precommit(self, context):
 | 
			
		||||
        """Allocate resources for a new port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the port.
 | 
			
		||||
 | 
			
		||||
        Create a new port, allocating resources as necessary in the
 | 
			
		||||
        database. Called inside transaction context on session. Call
 | 
			
		||||
        cannot block.  Raising an exception will result in a rollback
 | 
			
		||||
        of the current transaction.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_port_postcommit(self, context):
 | 
			
		||||
        """Create a port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the port.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction completes. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance.  Raising an exception will
 | 
			
		||||
        result in the deletion of the resource.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def update_port_precommit(self, context):
 | 
			
		||||
        """Update resources of a port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the new
 | 
			
		||||
        state of the port, as well as the original state prior
 | 
			
		||||
        to the update_port call.
 | 
			
		||||
 | 
			
		||||
        Called inside transaction context on session to complete a
 | 
			
		||||
        port update as defined by this mechanism driver. Raising an
 | 
			
		||||
        exception will result in rollback of the transaction.
 | 
			
		||||
 | 
			
		||||
        update_port_precommit is called for all changes to the port
 | 
			
		||||
        state. It is up to the mechanism driver to ignore state or
 | 
			
		||||
        state changes that it does not know or care about.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def update_port_postcommit(self, context):
 | 
			
		||||
        """Update a port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the new
 | 
			
		||||
        state of the port, as well as the original state prior
 | 
			
		||||
        to the update_port call.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction completes. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance.  Raising an exception will
 | 
			
		||||
        result in the deletion of the resource.
 | 
			
		||||
 | 
			
		||||
        update_port_postcommit is called for all changes to the port
 | 
			
		||||
        state. It is up to the mechanism driver to ignore state or
 | 
			
		||||
        state changes that it does not know or care about.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def delete_port_precommit(self, context):
 | 
			
		||||
        """Delete resources of a port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the current
 | 
			
		||||
        state of the port, prior to the call to delete it.
 | 
			
		||||
 | 
			
		||||
        Called inside transaction context on session. Runtime errors
 | 
			
		||||
        are not expected, but raising an exception will result in
 | 
			
		||||
        rollback of the transaction.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def delete_port_postcommit(self, context):
 | 
			
		||||
        """Delete a port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the current
 | 
			
		||||
        state of the port, prior to the call to delete it.
 | 
			
		||||
 | 
			
		||||
        Called after the transaction completes. Call can block, though
 | 
			
		||||
        will block the entire process so care should be taken to not
 | 
			
		||||
        drastically affect performance.  Runtime errors are not
 | 
			
		||||
        expected, and will not prevent the resource from being
 | 
			
		||||
        deleted.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def bind_port(self, context):
 | 
			
		||||
        """Attempt to bind a port.
 | 
			
		||||
 | 
			
		||||
        :param context: PortContext instance describing the port
 | 
			
		||||
 | 
			
		||||
        This method is called outside any transaction to attempt to
 | 
			
		||||
        establish a port binding using this mechanism driver. Bindings
 | 
			
		||||
        may be created at each of multiple levels of a hierarchical
 | 
			
		||||
        network, and are established from the top level downward. At
 | 
			
		||||
        each level, the mechanism driver determines whether it can
 | 
			
		||||
        bind to any of the network segments in the
 | 
			
		||||
        context.segments_to_bind property, based on the value of the
 | 
			
		||||
        context.host property, any relevant port or network
 | 
			
		||||
        attributes, and its own knowledge of the network topology. At
 | 
			
		||||
        the top level, context.segments_to_bind contains the static
 | 
			
		||||
        segments of the port's network. At each lower level of
 | 
			
		||||
        binding, it contains static or dynamic segments supplied by
 | 
			
		||||
        the driver that bound at the level above. If the driver is
 | 
			
		||||
        able to complete the binding of the port to any segment in
 | 
			
		||||
        context.segments_to_bind, it must call context.set_binding
 | 
			
		||||
        with the binding details. If it can partially bind the port,
 | 
			
		||||
        it must call context.continue_binding with the network
 | 
			
		||||
        segments to be used to bind at the next lower level.
 | 
			
		||||
 | 
			
		||||
        If the binding results are committed after bind_port returns,
 | 
			
		||||
        they will be seen by all mechanism drivers as
 | 
			
		||||
        update_port_precommit and update_port_postcommit calls. But if
 | 
			
		||||
        some other thread or process concurrently binds or updates the
 | 
			
		||||
        port, these binding results will not be committed, and
 | 
			
		||||
        update_port_precommit and update_port_postcommit will not be
 | 
			
		||||
        called on the mechanism drivers with these results. Because
 | 
			
		||||
        binding results can be discarded rather than committed,
 | 
			
		||||
        drivers should avoid making persistent state changes in
 | 
			
		||||
        bind_port, or else must ensure that such state changes are
 | 
			
		||||
        eventually cleaned up.
 | 
			
		||||
 | 
			
		||||
        Implementing this method explicitly declares the mechanism
 | 
			
		||||
        driver as having the intention to bind ports. This is inspected
 | 
			
		||||
        by the QoS service to identify the available QoS rules you
 | 
			
		||||
        can use with ports.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def _supports_port_binding(self):
 | 
			
		||||
        return self.__class__.bind_port != MechanismDriver.bind_port
 | 
			
		||||
 | 
			
		||||
    def check_vlan_transparency(self, context):
 | 
			
		||||
        """Check if the network supports vlan transparency.
 | 
			
		||||
 | 
			
		||||
        :param context: NetworkContext instance describing the network.
 | 
			
		||||
 | 
			
		||||
        Check if the network supports vlan transparency or not.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def get_workers(self):
 | 
			
		||||
        """Get any NeutronWorker instances that should have their own process
 | 
			
		||||
 | 
			
		||||
        Any driver that needs to run processes separate from the API or RPC
 | 
			
		||||
        workers, can return a sequence of NeutronWorker instances.
 | 
			
		||||
        """
 | 
			
		||||
        return ()
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def is_host_filtering_supported(cls):
 | 
			
		||||
        return (cls.filter_hosts_with_segment_access !=
 | 
			
		||||
                MechanismDriver.filter_hosts_with_segment_access)
 | 
			
		||||
 | 
			
		||||
    def filter_hosts_with_segment_access(
 | 
			
		||||
            self, context, segments, candidate_hosts, agent_getter):
 | 
			
		||||
        """Filter hosts with access to at least one segment.
 | 
			
		||||
 | 
			
		||||
        :returns: a set with a subset of candidate_hosts.
 | 
			
		||||
 | 
			
		||||
        A driver can overload this method to return a subset of candidate_hosts
 | 
			
		||||
        with the ones with access to at least one segment.
 | 
			
		||||
 | 
			
		||||
        Default implementation returns all hosts to disable filtering
 | 
			
		||||
        (backward compatibility).
 | 
			
		||||
        """
 | 
			
		||||
        return candidate_hosts
 | 
			
		||||
							
								
								
									
										0
									
								
								neutron_lib/tests/unit/plugins/ml2/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								neutron_lib/tests/unit/plugins/ml2/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										39
									
								
								neutron_lib/tests/unit/plugins/ml2/test_api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								neutron_lib/tests/unit/plugins/ml2/test_api.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
# 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.plugins.ml2 import api
 | 
			
		||||
from neutron_lib.tests import _base as base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _MechanismDriver(api.MechanismDriver):
 | 
			
		||||
    bind_port = lambda s, c: c
 | 
			
		||||
 | 
			
		||||
    def initialize(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestMechanismDriver(base.BaseTestCase):
 | 
			
		||||
 | 
			
		||||
    def test__supports_port_binding(self):
 | 
			
		||||
        self.assertTrue(_MechanismDriver()._supports_port_binding)
 | 
			
		||||
 | 
			
		||||
    def test_get_workers(self):
 | 
			
		||||
        self.assertEqual((), _MechanismDriver().get_workers())
 | 
			
		||||
 | 
			
		||||
    def test_filter_hosts_with_segment_access(self):
 | 
			
		||||
        dummy_token = ["X"]
 | 
			
		||||
        self.assertEqual(
 | 
			
		||||
            dummy_token,
 | 
			
		||||
            _MechanismDriver().filter_hosts_with_segment_access(
 | 
			
		||||
                dummy_token, dummy_token, dummy_token, dummy_token))
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
---
 | 
			
		||||
features:
 | 
			
		||||
  - The ML2 ``MechanismDriver`` class from ``neutron.plugins.ml2.driver_api``
 | 
			
		||||
    is now available in ``neutron_lib.plugins.ml2.api``.
 | 
			
		||||
		Reference in New Issue
	
	Block a user