Support for extensions in ML2
The current ML2 plugin supports only extensions defined in the plugin and it does not support any extensions in the mechanism drivers. The changes in this commit allows mechanism drivers to define new extensions. Change-Id: I28da19fabf6de2e9f0d687f875aaaa24c8bbc4f0 Implements: blueprint extensions-in-ml2
This commit is contained in:
parent
2ae77d0329
commit
feb3660344
@ -21,6 +21,11 @@
|
||||
# Example: mechanism_drivers = openvswitch,brocade
|
||||
# Example: mechanism_drivers = linuxbridge,brocade
|
||||
|
||||
# (ListOpt) Ordered list of extension driver entrypoints
|
||||
# to be loaded from the neutron.ml2.extension_drivers namespace.
|
||||
# extension_drivers =
|
||||
# Example: extension_drivers = anewextensiondriver
|
||||
|
||||
[ml2_type_flat]
|
||||
# (ListOpt) List of physical_network names with which flat networks
|
||||
# can be created. Use * to allow flat networks with arbitrary
|
||||
|
@ -679,6 +679,6 @@ def get_extensions_path():
|
||||
|
||||
|
||||
def append_api_extensions_path(paths):
|
||||
paths = [cfg.CONF.api_extensions_path] + paths
|
||||
paths = list(set([cfg.CONF.api_extensions_path] + paths))
|
||||
cfg.CONF.set_override('api_extensions_path',
|
||||
':'.join([p for p in paths if p]))
|
||||
|
@ -807,6 +807,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||
for route in subnet['routes']],
|
||||
'shared': subnet['shared']
|
||||
}
|
||||
# Call auxiliary extend functions, if any
|
||||
self._apply_dict_extend_functions(attributes.SUBNETS, res, subnet)
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _make_port_dict(self, port, fields=None,
|
||||
|
@ -30,6 +30,11 @@ ml2_opts = [
|
||||
help=_("An ordered list of networking mechanism driver "
|
||||
"entrypoints to be loaded from the "
|
||||
"neutron.ml2.mechanism_drivers namespace.")),
|
||||
cfg.ListOpt('extension_drivers',
|
||||
default=[],
|
||||
help=_("An ordered list of extension driver "
|
||||
"entrypoints to be loaded from the "
|
||||
"neutron.ml2.extension_drivers namespace.")),
|
||||
]
|
||||
|
||||
|
||||
|
@ -649,3 +649,158 @@ class MechanismDriver(object):
|
||||
that such state changes are eventually cleaned up.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class ExtensionDriver(object):
|
||||
"""Define stable abstract interface for ML2 extension drivers.
|
||||
|
||||
An extension driver extends the core resources implemented by the
|
||||
ML2 plugin with additional attributes. Methods that process create
|
||||
and update operations for these resources validate and persist
|
||||
values for extended attributes supplied through the API. Other
|
||||
methods extend the resource dictionaries returned from the API
|
||||
operations with the values of the extended attributes.
|
||||
"""
|
||||
|
||||
@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
|
||||
|
||||
@abc.abstractproperty
|
||||
def extension_alias(self):
|
||||
"""Supported extension alias.
|
||||
|
||||
Return the alias identifying the core API extension supported
|
||||
by this driver.
|
||||
"""
|
||||
pass
|
||||
|
||||
def process_create_network(self, session, data, result):
|
||||
"""Process extended attributes for create network.
|
||||
|
||||
:param session: database session
|
||||
:param data: dictionary of incoming network data
|
||||
:param result: network dictionary to extend
|
||||
|
||||
Called inside transaction context on session to validate and
|
||||
persist any extended network attributes defined by this
|
||||
driver. Extended attribute values must also be added to
|
||||
result.
|
||||
"""
|
||||
pass
|
||||
|
||||
def process_create_subnet(self, session, data, result):
|
||||
"""Process extended attributes for create subnet.
|
||||
|
||||
:param session: database session
|
||||
:param data: dictionary of incoming subnet data
|
||||
:param result: subnet dictionary to extend
|
||||
|
||||
Called inside transaction context on session to validate and
|
||||
persist any extended subnet attributes defined by this
|
||||
driver. Extended attribute values must also be added to
|
||||
result.
|
||||
"""
|
||||
pass
|
||||
|
||||
def process_create_port(self, session, data, result):
|
||||
"""Process extended attributes for create port.
|
||||
|
||||
:param session: database session
|
||||
:param data: dictionary of incoming port data
|
||||
:param result: port dictionary to extend
|
||||
|
||||
Called inside transaction context on session to validate and
|
||||
persist any extended port attributes defined by this
|
||||
driver. Extended attribute values must also be added to
|
||||
result.
|
||||
"""
|
||||
pass
|
||||
|
||||
def process_update_network(self, session, data, result):
|
||||
"""Process extended attributes for update network.
|
||||
|
||||
:param session: database session
|
||||
:param data: dictionary of incoming network data
|
||||
:param result: network dictionary to extend
|
||||
|
||||
Called inside transaction context on session to validate and
|
||||
update any extended network attributes defined by this
|
||||
driver. Extended attribute values, whether updated or not,
|
||||
must also be added to result.
|
||||
"""
|
||||
pass
|
||||
|
||||
def process_update_subnet(self, session, data, result):
|
||||
"""Process extended attributes for update subnet.
|
||||
|
||||
:param session: database session
|
||||
:param data: dictionary of incoming subnet data
|
||||
:param result: subnet dictionary to extend
|
||||
|
||||
Called inside transaction context on session to validate and
|
||||
update any extended subnet attributes defined by this
|
||||
driver. Extended attribute values, whether updated or not,
|
||||
must also be added to result.
|
||||
"""
|
||||
pass
|
||||
|
||||
def process_update_port(self, session, data, result):
|
||||
"""Process extended attributes for update port.
|
||||
|
||||
:param session: database session
|
||||
:param data: dictionary of incoming port data
|
||||
:param result: port dictionary to extend
|
||||
|
||||
Called inside transaction context on session to validate and
|
||||
update any extended port attributes defined by this
|
||||
driver. Extended attribute values, whether updated or not,
|
||||
must also be added to result.
|
||||
"""
|
||||
pass
|
||||
|
||||
def extend_network_dict(self, session, result):
|
||||
"""Add extended attributes to network dictionary.
|
||||
|
||||
:param session: database session
|
||||
:param result: network dictionary to extend
|
||||
|
||||
Called inside transaction context on session to add any
|
||||
extended attributes defined by this driver to a network
|
||||
dictionary to be used for mechanism driver calls and/or
|
||||
returned as the result of a network operation.
|
||||
"""
|
||||
pass
|
||||
|
||||
def extend_subnet_dict(self, session, result):
|
||||
"""Add extended attributes to subnet dictionary.
|
||||
|
||||
:param session: database session
|
||||
:param result: subnet dictionary to extend
|
||||
|
||||
Called inside transaction context on session to add any
|
||||
extended attributes defined by this driver to a subnet
|
||||
dictionary to be used for mechanism driver calls and/or
|
||||
returned as the result of a subnet operation.
|
||||
"""
|
||||
pass
|
||||
|
||||
def extend_port_dict(self, session, result):
|
||||
"""Add extended attributes to port dictionary.
|
||||
|
||||
:param session: database session
|
||||
:param result: port dictionary to extend
|
||||
|
||||
Called inside transaction context on session to add any
|
||||
extended attributes defined by this driver to a port
|
||||
dictionary to be used for mechanism driver calls and/or
|
||||
returned as the result of a port operation.
|
||||
"""
|
||||
pass
|
||||
|
@ -573,3 +573,107 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
||||
LOG.warning(_("Failed to bind port %(port)s on host %(host)s"),
|
||||
{'port': context._port['id'],
|
||||
'host': binding.host})
|
||||
|
||||
|
||||
class ExtensionManager(stevedore.named.NamedExtensionManager):
|
||||
"""Manage extension drivers using drivers."""
|
||||
|
||||
def __init__(self):
|
||||
# Ordered list of extension drivers, defining
|
||||
# the order in which the drivers are called.
|
||||
self.ordered_ext_drivers = []
|
||||
|
||||
LOG.info(_("Configured extension driver names: %s"),
|
||||
cfg.CONF.ml2.extension_drivers)
|
||||
super(ExtensionManager, self).__init__('neutron.ml2.extension_drivers',
|
||||
cfg.CONF.ml2.extension_drivers,
|
||||
invoke_on_load=True,
|
||||
name_order=True)
|
||||
LOG.info(_("Loaded extension driver names: %s"), self.names())
|
||||
self._register_drivers()
|
||||
|
||||
def _register_drivers(self):
|
||||
"""Register all extension drivers.
|
||||
|
||||
This method should only be called once in the ExtensionManager
|
||||
constructor.
|
||||
"""
|
||||
for ext in self:
|
||||
self.ordered_ext_drivers.append(ext)
|
||||
LOG.info(_("Registered extension drivers: %s"),
|
||||
[driver.name for driver in self.ordered_ext_drivers])
|
||||
|
||||
def initialize(self):
|
||||
# Initialize each driver in the list.
|
||||
for driver in self.ordered_ext_drivers:
|
||||
LOG.info(_("Initializing extension driver '%s'"), driver.name)
|
||||
driver.obj.initialize()
|
||||
|
||||
def extension_aliases(self):
|
||||
exts = []
|
||||
for driver in self.ordered_ext_drivers:
|
||||
alias = driver.obj.extension_alias
|
||||
exts.append(alias)
|
||||
LOG.info(_("Got %(alias)s extension from driver '%(drv)s'"),
|
||||
{'alias': alias, 'drv': driver.name})
|
||||
return exts
|
||||
|
||||
def _call_on_ext_drivers(self, method_name, session, data, result):
|
||||
"""Helper method for calling a method across all extension drivers."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
try:
|
||||
getattr(driver.obj, method_name)(session, data, result)
|
||||
except Exception:
|
||||
LOG.exception(
|
||||
_("Extension driver '%(name)s' failed in %(method)s"),
|
||||
{'name': driver.name, 'method': method_name}
|
||||
)
|
||||
|
||||
def process_create_network(self, session, data, result):
|
||||
"""Notify all extension drivers during network creation."""
|
||||
self._call_on_ext_drivers("process_create_network", session, data,
|
||||
result)
|
||||
|
||||
def process_update_network(self, session, data, result):
|
||||
"""Notify all extension drivers during network update."""
|
||||
self._call_on_ext_drivers("process_update_network", session, data,
|
||||
result)
|
||||
|
||||
def process_create_subnet(self, session, data, result):
|
||||
"""Notify all extension drivers during subnet creation."""
|
||||
self._call_on_ext_drivers("process_create_subnet", session, data,
|
||||
result)
|
||||
|
||||
def process_update_subnet(self, session, data, result):
|
||||
"""Notify all extension drivers during subnet update."""
|
||||
self._call_on_ext_drivers("process_update_subnet", session, data,
|
||||
result)
|
||||
|
||||
def process_create_port(self, session, data, result):
|
||||
"""Notify all extension drivers during port creation."""
|
||||
self._call_on_ext_drivers("process_create_port", session, data, result)
|
||||
|
||||
def process_update_port(self, session, data, result):
|
||||
"""Notify all extension drivers during port update."""
|
||||
self._call_on_ext_drivers("process_update_port", session, data, result)
|
||||
|
||||
def extend_network_dict(self, session, result):
|
||||
"""Notify all extension drivers to extend network dictionary."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
driver.obj.extend_network_dict(session, result)
|
||||
LOG.info(_("Extended network dict for driver '%(drv)s'"),
|
||||
{'drv': driver.name})
|
||||
|
||||
def extend_subnet_dict(self, session, result):
|
||||
"""Notify all extension drivers to extend subnet dictionary."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
driver.obj.extend_subnet_dict(session, result)
|
||||
LOG.info(_("Extended subnet dict for driver '%(drv)s'"),
|
||||
{'drv': driver.name})
|
||||
|
||||
def extend_port_dict(self, session, result):
|
||||
"""Notify all extension drivers to extend port dictionary."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
driver.obj.extend_port_dict(session, result)
|
||||
LOG.info(_("Extended port dict for driver '%(drv)s'"),
|
||||
{'drv': driver.name})
|
||||
|
@ -35,6 +35,7 @@ from neutron.common import utils
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import agentschedulers_db
|
||||
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import dvr_mac_db
|
||||
from neutron.db import external_net_db
|
||||
@ -110,6 +111,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
def supported_extension_aliases(self):
|
||||
if not hasattr(self, '_aliases'):
|
||||
aliases = self._supported_extension_aliases[:]
|
||||
aliases += self.extension_manager.extension_aliases()
|
||||
sg_rpc.disable_security_group_extension_by_config(aliases)
|
||||
self._aliases = aliases
|
||||
return self._aliases
|
||||
@ -117,9 +119,11 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
def __init__(self):
|
||||
# First load drivers, then initialize DB, then initialize drivers
|
||||
self.type_manager = managers.TypeManager()
|
||||
self.extension_manager = managers.ExtensionManager()
|
||||
self.mechanism_manager = managers.MechanismManager()
|
||||
super(Ml2Plugin, self).__init__()
|
||||
self.type_manager.initialize()
|
||||
self.extension_manager.initialize()
|
||||
self.mechanism_manager.initialize()
|
||||
# bulk support depends on the underlying drivers
|
||||
self.__native_bulk_support = self.mechanism_manager.native_bulk_support
|
||||
@ -411,6 +415,31 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.PORTS, ['_ml2_extend_port_dict_binding'])
|
||||
|
||||
# Register extend dict methods for network and port resources.
|
||||
# Each mechanism driver that supports extend attribute for the resources
|
||||
# can add those attribute to the result.
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.NETWORKS, ['_ml2_md_extend_network_dict'])
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.PORTS, ['_ml2_md_extend_port_dict'])
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.SUBNETS, ['_ml2_md_extend_subnet_dict'])
|
||||
|
||||
def _ml2_md_extend_network_dict(self, result, netdb):
|
||||
session = db_api.get_session()
|
||||
with session.begin(subtransactions=True):
|
||||
self.extension_manager.extend_network_dict(session, result)
|
||||
|
||||
def _ml2_md_extend_port_dict(self, result, portdb):
|
||||
session = db_api.get_session()
|
||||
with session.begin(subtransactions=True):
|
||||
self.extension_manager.extend_port_dict(session, result)
|
||||
|
||||
def _ml2_md_extend_subnet_dict(self, result, subnetdb):
|
||||
session = db_api.get_session()
|
||||
with session.begin(subtransactions=True):
|
||||
self.extension_manager.extend_subnet_dict(session, result)
|
||||
|
||||
# Note - The following hook methods have "ml2" in their names so
|
||||
# that they are not called twice during unit tests due to global
|
||||
# registration of hooks in portbindings_db.py used by other
|
||||
@ -460,6 +489,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
with session.begin(subtransactions=True):
|
||||
self._ensure_default_security_group(context, tenant_id)
|
||||
result = super(Ml2Plugin, self).create_network(context, network)
|
||||
self.extension_manager.process_create_network(session, net_data,
|
||||
result)
|
||||
self._process_l3_create(context, result, net_data)
|
||||
net_data['id'] = result['id']
|
||||
self.type_manager.create_network_segments(context, net_data,
|
||||
@ -487,6 +518,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
updated_network = super(Ml2Plugin, self).update_network(context,
|
||||
id,
|
||||
network)
|
||||
self.extension_manager.process_update_network(session, network,
|
||||
original_network)
|
||||
self._process_l3_update(context, updated_network,
|
||||
network['network'])
|
||||
self.type_manager._extend_network_dict_provider(context,
|
||||
@ -627,6 +660,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
result = super(Ml2Plugin, self).create_subnet(context, subnet)
|
||||
self.extension_manager.process_create_subnet(session, subnet,
|
||||
result)
|
||||
mech_context = driver_context.SubnetContext(self, context, result)
|
||||
self.mechanism_manager.create_subnet_precommit(mech_context)
|
||||
|
||||
@ -645,6 +680,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
original_subnet = super(Ml2Plugin, self).get_subnet(context, id)
|
||||
updated_subnet = super(Ml2Plugin, self).update_subnet(
|
||||
context, id, subnet)
|
||||
self.extension_manager.process_update_subnet(session, subnet,
|
||||
original_subnet)
|
||||
mech_context = driver_context.SubnetContext(
|
||||
self, context, updated_subnet, original_subnet=original_subnet)
|
||||
self.mechanism_manager.update_subnet_precommit(mech_context)
|
||||
@ -737,6 +774,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
sgids = self._get_security_groups_on_port(context, port)
|
||||
dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, [])
|
||||
result = super(Ml2Plugin, self).create_port(context, port)
|
||||
self.extension_manager.process_create_port(session, attrs, result)
|
||||
self._process_port_create_security_group(context, result, sgids)
|
||||
network = self.get_network(context, result['network_id'])
|
||||
binding = db.add_port_binding(session, result['id'])
|
||||
@ -791,6 +829,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
original_port = self._make_port_dict(port_db)
|
||||
updated_port = super(Ml2Plugin, self).update_port(context, id,
|
||||
port)
|
||||
self.extension_manager.process_update_port(session, attrs,
|
||||
original_port)
|
||||
if addr_pair.ADDRESS_PAIRS in port['port']:
|
||||
need_port_update_notify |= (
|
||||
self.update_address_pairs_on_port(context, id, port,
|
||||
|
0
neutron/tests/unit/ml2/extensions/__init__.py
Normal file
0
neutron/tests/unit/ml2/extensions/__init__.py
Normal file
69
neutron/tests/unit/ml2/extensions/test_extension.py
Normal file
69
neutron/tests/unit/ml2/extensions/test_extension.py
Normal file
@ -0,0 +1,69 @@
|
||||
# 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.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
|
||||
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'networks': {
|
||||
'network_extension': {'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True,
|
||||
'enforce_policy': True},
|
||||
},
|
||||
'subnets': {
|
||||
'subnet_extension': {'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True,
|
||||
'enforce_policy': True},
|
||||
},
|
||||
'ports': {
|
||||
'port_extension': {'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True,
|
||||
'enforce_policy': True},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Test_extension(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "ML2 test extension"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "test_extension"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return _("Adds test attributes to core resources.")
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return ("http://docs.openstack.org/ext/neutron/ml2/test/"
|
||||
"test_extension/api/v1.0")
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2014-07-16T10:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return EXTENDED_ATTRIBUTES_2_0
|
||||
else:
|
||||
return {}
|
66
neutron/tests/unit/ml2/test_extension_driver_api.py
Normal file
66
neutron/tests/unit/ml2/test_extension_driver_api.py
Normal file
@ -0,0 +1,66 @@
|
||||
# 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.api import extensions
|
||||
from neutron.plugins.ml2 import config
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.tests.unit.ml2 import extensions as test_extensions
|
||||
from neutron.tests.unit.ml2 import test_ml2_plugin
|
||||
|
||||
|
||||
class ExtensionDriverTestCase(test_ml2_plugin.Ml2PluginV2TestCase):
|
||||
|
||||
_extension_drivers = ['test']
|
||||
|
||||
def setUp(self):
|
||||
config.cfg.CONF.set_override('extension_drivers',
|
||||
self._extension_drivers,
|
||||
group='ml2')
|
||||
super(ExtensionDriverTestCase, self).setUp()
|
||||
|
||||
def test_network_attr(self):
|
||||
with self.network() as network:
|
||||
ent = network['network'].get('network_extension')
|
||||
self.assertIsNotNone(ent)
|
||||
|
||||
def test_subnet_attr(self):
|
||||
with self.subnet() as subnet:
|
||||
ent = subnet['subnet'].get('subnet_extension')
|
||||
self.assertIsNotNone(ent)
|
||||
|
||||
def test_port_attr(self):
|
||||
with self.port() as port:
|
||||
ent = port['port'].get('port_extension')
|
||||
self.assertIsNotNone(ent)
|
||||
|
||||
|
||||
class TestExtensionDriver(api.ExtensionDriver):
|
||||
_supported_extension_alias = 'test_extension'
|
||||
|
||||
def initialize(self):
|
||||
self.network_extension = 'Test_Network_Extension'
|
||||
self.subnet_extension = 'Test_Subnet_Extension'
|
||||
self.port_extension = 'Test_Port_Extension'
|
||||
extensions.append_api_extensions_path(test_extensions.__path__)
|
||||
|
||||
@property
|
||||
def extension_alias(self):
|
||||
return self._supported_extension_alias
|
||||
|
||||
def process_create_network(self, session, data, result):
|
||||
result['network_extension'] = self.network_extension
|
||||
|
||||
def process_create_subnet(self, session, data, result):
|
||||
result['subnet_extension'] = self.subnet_extension
|
||||
|
||||
def process_create_port(self, session, data, result):
|
||||
result['port_extension'] = self.port_extension
|
@ -176,6 +176,8 @@ neutron.ml2.mechanism_drivers =
|
||||
fslsdn = neutron.plugins.ml2.drivers.mechanism_fslsdn:FslsdnMechanismDriver
|
||||
sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver:SriovNicSwitchMechanismDriver
|
||||
nuage = neutron.plugins.ml2.drivers.mech_nuage.driver:NuageMechanismDriver
|
||||
neutron.ml2.extension_drivers =
|
||||
test = neutron.tests.unit.ml2.test_extension_driver_api:TestExtensionDriver
|
||||
neutron.openstack.common.cache.backends =
|
||||
memory = neutron.openstack.common.cache._backends.memory:MemoryBackend
|
||||
# These are for backwards compat with Icehouse notification_driver configuration values
|
||||
@ -186,7 +188,6 @@ oslo.messaging.notify.drivers =
|
||||
neutron.openstack.common.notifier.rpc_notifier = oslo.messaging.notify._impl_messaging:MessagingDriver
|
||||
neutron.openstack.common.notifier.test_notifier = oslo.messaging.notify._impl_test:TestDriver
|
||||
|
||||
|
||||
[build_sphinx]
|
||||
all_files = 1
|
||||
build-dir = doc/build
|
||||
|
Loading…
Reference in New Issue
Block a user