Moving VLAN Transparency support from core to extension
* Moving VLAN Transparency support from core to extension * Remove the older unit tests and add new corresponding ones DocImpact Closes-Bug: #1434667 Change-Id: Ic551475ed7b64aad9627a57abb0df41acc19bfc1
This commit is contained in:
parent
bc66a04ae4
commit
809e434d2d
|
@ -707,9 +707,6 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||
'validate': {'type:string': TENANT_ID_MAX_LEN},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'vlan_transparent': {'allow_post': True, 'allow_put': False,
|
||||
'convert_to': convert_to_boolean,
|
||||
'default': False, 'is_visible': True},
|
||||
SHARED: {'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': False,
|
||||
|
|
|
@ -844,9 +844,14 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||
'mtu': network.get('mtu', constants.DEFAULT_NETWORK_MTU),
|
||||
'status': network['status'],
|
||||
'shared': network['shared'],
|
||||
'vlan_transparent': network['vlan_transparent'],
|
||||
'subnets': [subnet['id']
|
||||
for subnet in network['subnets']]}
|
||||
# TODO(pritesh): Move vlan_transparent to the extension module.
|
||||
# vlan_transparent here is only added if the vlantransparent
|
||||
# extension is enabled.
|
||||
if ('vlan_transparent' in network and network['vlan_transparent'] !=
|
||||
attributes.ATTR_NOT_SPECIFIED):
|
||||
res['vlan_transparent'] = network['vlan_transparent']
|
||||
# Call auxiliary extend functions, if any
|
||||
if process_extensions:
|
||||
self._apply_dict_extend_functions(
|
||||
|
@ -951,8 +956,13 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||
'admin_state_up': n['admin_state_up'],
|
||||
'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU),
|
||||
'shared': n['shared'],
|
||||
'vlan_transparent': n.get('vlan_transparent', False),
|
||||
'status': n.get('status', constants.NET_STATUS_ACTIVE)}
|
||||
# TODO(pritesh): Move vlan_transparent to the extension module.
|
||||
# vlan_transparent here is only added if the vlantransparent
|
||||
# extension is enabled.
|
||||
if ('vlan_transparent' in n and n['vlan_transparent'] !=
|
||||
attributes.ATTR_NOT_SPECIFIED):
|
||||
args['vlan_transparent'] = n['vlan_transparent']
|
||||
network = models_v2.Network(**args)
|
||||
context.session.add(network)
|
||||
return self._make_network_dict(network, process_extensions=False)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# Copyright (c) 2015 Cisco Systems, 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 neutron.api.v2 import attributes
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.extensions import vlantransparent
|
||||
|
||||
|
||||
class Vlantransparent_db_mixin(object):
|
||||
"""Mixin class to add vlan transparent methods to db_base_plugin_v2."""
|
||||
|
||||
def _extend_network_dict_vlan_transparent(self, network_res, network_db):
|
||||
network_res[vlantransparent.VLANTRANSPARENT] = (
|
||||
network_db.vlan_transparent)
|
||||
return network_res
|
||||
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.NETWORKS, ['_extend_network_dict_vlan_transparent'])
|
|
@ -0,0 +1,75 @@
|
|||
# Copyright (c) 2015 Cisco Systems, 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_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common import exceptions as nexception
|
||||
from neutron.i18n import _LI
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VlanTransparencyDriverError(nexception.NeutronException):
|
||||
"""Vlan Transparency not supported by all mechanism drivers."""
|
||||
message = _("Backend does not support VLAN Transparency.")
|
||||
|
||||
|
||||
VLANTRANSPARENT = 'vlan_transparent'
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'networks': {
|
||||
VLANTRANSPARENT: {'allow_post': True, 'allow_put': False,
|
||||
'convert_to': attributes.convert_to_boolean,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def disable_extension_by_config(aliases):
|
||||
if not cfg.CONF.vlan_transparent:
|
||||
if 'vlan-transparent' in aliases:
|
||||
aliases.remove('vlan-transparent')
|
||||
LOG.info(_LI('Disabled vlantransparent extension.'))
|
||||
|
||||
|
||||
class Vlantransparent(object):
|
||||
"""Extension class supporting vlan transparent networks."""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Vlantransparent"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "vlan-transparent"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Provides Vlan Transparent Networks"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/vlantransparent/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2015-03-23T09:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return EXTENDED_ATTRIBUTES_2_0
|
||||
else:
|
||||
return {}
|
|
@ -21,8 +21,3 @@ from neutron.common import exceptions
|
|||
class MechanismDriverError(exceptions.NeutronException):
|
||||
"""Mechanism driver call failed."""
|
||||
message = _("%(method)s failed.")
|
||||
|
||||
|
||||
class VlanTransparencyError(exceptions.NeutronException):
|
||||
"""Vlan Transparency not supported by all mechanism drivers."""
|
||||
message = _("Backend does not support VLAN Transparency.")
|
||||
|
|
|
@ -48,3 +48,7 @@ class LinuxbridgeMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
|||
|
||||
def get_mappings(self, agent):
|
||||
return agent['configurations'].get('interface_mappings', {})
|
||||
|
||||
def check_vlan_transparency(self, context):
|
||||
"""Linuxbridge driver vlan transparency support."""
|
||||
return True
|
||||
|
|
|
@ -50,3 +50,7 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
|||
|
||||
def get_mappings(self, agent):
|
||||
return agent['configurations'].get('bridge_mappings', {})
|
||||
|
||||
def check_vlan_transparency(self, context):
|
||||
"""Currently Openvswitch driver doesn't support vlan transparency."""
|
||||
return False
|
||||
|
|
|
@ -22,6 +22,7 @@ from neutron.common import exceptions as exc
|
|||
from neutron.extensions import multiprovidernet as mpnet
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.extensions import providernet as provider
|
||||
from neutron.extensions import vlantransparent
|
||||
from neutron.i18n import _LE, _LI
|
||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
||||
from neutron.plugins.ml2 import db
|
||||
|
@ -297,14 +298,17 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
|||
"""Helper method for checking vlan transparecncy support.
|
||||
|
||||
:param context: context parameter to pass to each method call
|
||||
:raises: neutron.plugins.ml2.common.VlanTransparencyError
|
||||
if any mechanism driver doesn't support vlan transparency.
|
||||
:raises: neutron.extensions.vlantransparent.
|
||||
VlanTransparencyDriverError if any mechanism driver doesn't
|
||||
support vlan transparency.
|
||||
"""
|
||||
if not cfg.CONF.vlan_transparent:
|
||||
if context.current['vlan_transparent'] is None:
|
||||
return
|
||||
for driver in self.ordered_mech_drivers:
|
||||
if driver.obj.check_vlan_transparency(context) is False:
|
||||
raise ml2_exc.VlanTransparencyError()
|
||||
|
||||
if context.current['vlan_transparent']:
|
||||
for driver in self.ordered_mech_drivers:
|
||||
if not driver.obj.check_vlan_transparency(context):
|
||||
raise vlantransparent.VlanTransparencyDriverError()
|
||||
|
||||
def _call_on_drivers(self, method_name, context,
|
||||
continue_on_failure=False):
|
||||
|
|
|
@ -56,12 +56,14 @@ from neutron.db import models_v2
|
|||
from neutron.db import netmtu_db
|
||||
from neutron.db import quota_db # noqa
|
||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||
from neutron.db import vlantransparent_db
|
||||
from neutron.extensions import allowedaddresspairs as addr_pair
|
||||
from neutron.extensions import extra_dhcp_opt as edo_ext
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.extensions import portsecurity as psec
|
||||
from neutron.extensions import providernet as provider
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
from neutron.extensions import vlantransparent
|
||||
from neutron.i18n import _LE, _LI, _LW
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import uuidutils
|
||||
|
@ -90,6 +92,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||
addr_pair_db.AllowedAddressPairsMixin,
|
||||
vlantransparent_db.Vlantransparent_db_mixin,
|
||||
extradhcpopt_db.ExtraDhcpOptMixin,
|
||||
netmtu_db.Netmtu_db_mixin):
|
||||
|
||||
|
@ -115,7 +118,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
"dhcp_agent_scheduler",
|
||||
"multi-provider", "allowed-address-pairs",
|
||||
"extra_dhcp_opt", "subnet_allocation",
|
||||
"net-mtu"]
|
||||
"net-mtu", "vlan-transparent"]
|
||||
|
||||
@property
|
||||
def supported_extension_aliases(self):
|
||||
|
@ -123,6 +126,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
aliases = self._supported_extension_aliases[:]
|
||||
aliases += self.extension_manager.extension_aliases()
|
||||
sg_rpc.disable_security_group_extension_by_config(aliases)
|
||||
vlantransparent.disable_extension_by_config(aliases)
|
||||
self._aliases = aliases
|
||||
return self._aliases
|
||||
|
||||
|
|
|
@ -94,7 +94,6 @@ class PluginClientFixture(AbstractClientFixture):
|
|||
# Supply defaults that are expected to be set by the api
|
||||
# framwork
|
||||
kwargs.setdefault('admin_state_up', True)
|
||||
kwargs.setdefault('vlan_transparent', False)
|
||||
kwargs.setdefault('shared', False)
|
||||
data = dict(network=kwargs)
|
||||
result = self.plugin.create_network(self.ctx, data)
|
||||
|
|
|
@ -766,7 +766,6 @@ class JSONV2TestCase(APIv2TestBase, testlib_api.WebTestCase):
|
|||
net_id = _uuid()
|
||||
initial_input = {'network': {'name': 'net1', 'tenant_id': _uuid()}}
|
||||
full_input = {'network': {'admin_state_up': True,
|
||||
'vlan_transparent': False,
|
||||
'shared': False}}
|
||||
full_input['network'].update(initial_input['network'])
|
||||
|
||||
|
@ -801,7 +800,6 @@ class JSONV2TestCase(APIv2TestBase, testlib_api.WebTestCase):
|
|||
# tenant_id should be fetched from env
|
||||
initial_input = {'network': {'name': 'net1'}}
|
||||
full_input = {'network': {'admin_state_up': True,
|
||||
'vlan_transparent': False,
|
||||
'shared': False, 'tenant_id': tenant_id}}
|
||||
full_input['network'].update(initial_input['network'])
|
||||
|
||||
|
@ -1421,8 +1419,7 @@ class ExtensionTestCase(base.BaseTestCase):
|
|||
net_id = _uuid()
|
||||
initial_input = {'network': {'name': 'net1', 'tenant_id': _uuid(),
|
||||
'v2attrs:something_else': "abc"}}
|
||||
data = {'network': {'admin_state_up': True, 'shared': False,
|
||||
'vlan_transparent': False}}
|
||||
data = {'network': {'admin_state_up': True, 'shared': False}}
|
||||
data['network'].update(initial_input['network'])
|
||||
|
||||
return_value = {'subnets': [], 'status': "ACTIVE",
|
||||
|
|
|
@ -2242,12 +2242,6 @@ class TestNetworksV2(NeutronDbPluginV2TestCase):
|
|||
self.assertEqual(ctx_manager.exception.code,
|
||||
webob.exc.HTTPForbidden.code)
|
||||
|
||||
def test_create_network_vlan_transparent(self):
|
||||
name = "vlan_transparent"
|
||||
cfg.CONF.set_override('vlan_transparent', True)
|
||||
with self.network(name=name, vlan_transparent=True) as net:
|
||||
self.assertEqual(net['network']['vlan_transparent'], True)
|
||||
|
||||
def test_update_network(self):
|
||||
with self.network() as network:
|
||||
data = {'network': {'name': 'a_brand_new_name'}}
|
||||
|
|
|
@ -139,7 +139,6 @@ class ProvidernetExtensionTestCase(testlib_api.WebTestCase):
|
|||
exp_input = {'network': data}
|
||||
exp_input['network'].update({'admin_state_up': True,
|
||||
'tenant_id': 'an_admin',
|
||||
'vlan_transparent': False,
|
||||
'shared': False})
|
||||
instance.create_network.assert_called_with(mock.ANY,
|
||||
network=exp_input)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# Copyright (c) 2015 Cisco Systems 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_config import cfg
|
||||
from webob import exc as web_exc
|
||||
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import vlantransparent_db as vlt_db
|
||||
from neutron.extensions import vlantransparent as vlt
|
||||
from neutron import quota
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
class VlanTransparentExtensionManager(object):
|
||||
|
||||
def get_resources(self):
|
||||
return []
|
||||
|
||||
def get_actions(self):
|
||||
return []
|
||||
|
||||
def get_request_extensions(self):
|
||||
return []
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
return vlt.get_extended_resources(version)
|
||||
|
||||
|
||||
class VlanTransparentExtensionTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
vlt_db.Vlantransparent_db_mixin):
|
||||
"""Test plugin to mixin the VLAN transparent extensions."""
|
||||
|
||||
supported_extension_aliases = ["vlan-transparent"]
|
||||
|
||||
|
||||
class VlanTransparentExtensionTestCase(test_db_base_plugin_v2.TestNetworksV2):
|
||||
fmt = 'json'
|
||||
|
||||
def setUp(self):
|
||||
plugin = ('neutron.tests.unit.extensions.test_vlantransparent.'
|
||||
'VlanTransparentExtensionTestPlugin')
|
||||
|
||||
# Save the global RESOURCE_ATTRIBUTE_MAP
|
||||
self.saved_attr_map = {}
|
||||
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
|
||||
self.saved_attr_map[resource] = attrs.copy()
|
||||
|
||||
# Update the plugin and extensions path
|
||||
self.setup_coreplugin(plugin)
|
||||
cfg.CONF.set_override('allow_pagination', True)
|
||||
cfg.CONF.set_override('allow_sorting', True)
|
||||
ext_mgr = VlanTransparentExtensionManager()
|
||||
self.addCleanup(self._restore_attribute_map)
|
||||
super(VlanTransparentExtensionTestCase, self).setUp(plugin=plugin,
|
||||
ext_mgr=ext_mgr)
|
||||
|
||||
quota.QUOTAS._driver = None
|
||||
cfg.CONF.set_override('quota_driver', 'neutron.quota.ConfDriver',
|
||||
group='QUOTAS')
|
||||
|
||||
def _restore_attribute_map(self):
|
||||
# Restore the global RESOURCE_ATTRIBUTE_MAP
|
||||
attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
|
||||
|
||||
def test_network_create_with_vlan_transparent_attr(self):
|
||||
vlantrans = {'vlan_transparent': True}
|
||||
with self.network(name='net1', **vlantrans) as net:
|
||||
req = self.new_show_request('networks', net['network']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
self.assertEqual(net['network']['name'],
|
||||
res['network']['name'])
|
||||
self.assertEqual(True, res['network'][vlt.VLANTRANSPARENT])
|
||||
|
||||
def test_network_create_with_bad_vlan_transparent_attr(self):
|
||||
vlantrans = {'vlan_transparent': "abc"}
|
||||
with testlib_api.ExpectedException(
|
||||
web_exc.HTTPClientError) as ctx_manager:
|
||||
with self.network(name='net1', **vlantrans):
|
||||
pass
|
||||
self.assertEqual(web_exc.HTTPClientError.code,
|
||||
ctx_manager.exception.code)
|
||||
|
||||
def test_network_update_with_vlan_transparent_exception(self):
|
||||
with self.network(name='net1') as net:
|
||||
self._update('networks', net['network']['id'],
|
||||
{'network': {vlt.VLANTRANSPARENT: False}},
|
||||
web_exc.HTTPBadRequest.code)
|
||||
req = self.new_show_request('networks', net['network']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
self.assertEqual(net['network']['name'],
|
||||
res['network']['name'])
|
||||
self.assertEqual(None, res['network'][vlt.VLANTRANSPARENT])
|
Loading…
Reference in New Issue