context.session.add(router_db)
if has_gw_info:
self._update_router_gw_info(context, router_db['id'], gw_info)
- return self._make_router_dict(router_db)
+ return self._make_router_dict(router_db, process_extensions=False)
def update_router(self, context, id, router):
r = router['router']
class L3_NAT_db_mixin(l3_db.L3_NAT_db_mixin):
"""Mixin class to add configurable gateway modes."""
- def _make_router_dict(self, router, fields=None):
- res = super(L3_NAT_db_mixin, self)._make_router_dict(router)
+ def _make_router_dict(self, router, fields=None, process_extensions=True):
+ res = super(L3_NAT_db_mixin, self)._make_router_dict(
+ router, process_extensions=process_extensions)
if router['gw_port_id']:
nw_id = router.gw_port['network_id']
res[EXTERNAL_GW_INFO] = {'network_id': nw_id,
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 OpenStack Foundation
+#
+# 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.
+#
+
+"""nvp_dist_router
+
+Revision ID: 40dffbf4b549
+Revises: 63afba73813
+Create Date: 2013-08-21 18:00:26.214923
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '40dffbf4b549'
+down_revision = '63afba73813'
+
+# Change to ['*'] if this migration applies to all plugins
+
+migration_for_plugins = [
+ 'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2'
+]
+
+from alembic import op
+import sqlalchemy as sa
+
+from neutron.db import migration
+
+
+def upgrade(active_plugins=None, options=None):
+ if not migration.should_run(active_plugins, migration_for_plugins):
+ return
+
+ op.create_table(
+ 'nsxrouterextattributess',
+ sa.Column('router_id', sa.String(length=36), nullable=False),
+ sa.Column('distributed', sa.Boolean(), nullable=False),
+ sa.ForeignKeyConstraint(
+ ['router_id'], ['routers.id'], ondelete='CASCADE'),
+ sa.PrimaryKeyConstraint('router_id')
+ )
+
+
+def downgrade(active_plugins=None, options=None):
+ if not migration.should_run(active_plugins, migration_for_plugins):
+ return
+
+ op.drop_table('nsxrouterextattributess')
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.common import metadata_access as nvp_meta
from neutron.plugins.nicira.common import securitygroups as nvp_sec
+from neutron.plugins.nicira.dbexts import distributedrouter as dist_rtr
from neutron.plugins.nicira.dbexts import maclearning as mac_db
from neutron.plugins.nicira.dbexts import nicira_db
from neutron.plugins.nicira.dbexts import nicira_networkgw_db as networkgw_db
class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
+ dist_rtr.DistributedRouter_mixin,
portbindings_db.PortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
securitygroups_db.SecurityGroupDbMixin,
supported_extension_aliases = ["agent",
"binding",
"dhcp_agent_scheduler",
+ "dist-router",
"ext-gw-mode",
"extraroute",
"mac-learning",
"provider",
"quotas",
"router",
- "security-group", ]
+ "security-group"]
__native_bulk_support = True
def __init__(self):
+ # TODO(salv-orlando): Replace These dicts with
+ # collections.defaultdict for better handling of default values
# Routines for managing logical ports in NVP
self._port_drivers = {
'create': {l3_db.DEVICE_OWNER_ROUTER_GW:
if ext_net.subnets:
ext_subnet = ext_net.subnets[0]
nexthop = ext_subnet.gateway_ip
- lrouter = nvplib.create_lrouter(self.cluster, tenant_id,
- router['router']['name'],
- nexthop)
+ distributed = r.get('distributed')
+ lrouter = nvplib.create_lrouter(
+ self.cluster, tenant_id, router['router']['name'], nexthop,
+ distributed=attr.is_attr_set(distributed) and distributed)
# Use NVP identfier for Neutron resource
- router['router']['id'] = lrouter['uuid']
+ r['id'] = lrouter['uuid']
+ # Update 'distributed' with value returned from NVP
+ # This will be useful for setting the value if the API request
+ # did not specify any value for the 'distributed' attribute
+ r['distributed'] = lrouter['distributed']
except NvpApiClient.NvpApiException:
raise nvp_exc.NvpPluginException(
err_msg=_("Unable to create logical router on NVP Platform"))
err_msg=_("Unable to create router %s") % r['name'])
with context.session.begin(subtransactions=True):
- router_db = l3_db.Router(id=lrouter['uuid'],
- tenant_id=tenant_id,
- name=r['name'],
- admin_state_up=r['admin_state_up'],
- status="ACTIVE")
- context.session.add(router_db)
+ # Transaction nesting is needed to avoid foreign key violations
+ # when processing the service provider binding
+ with context.session.begin(subtransactions=True):
+ router_db = l3_db.Router(id=lrouter['uuid'],
+ tenant_id=tenant_id,
+ name=r['name'],
+ admin_state_up=r['admin_state_up'],
+ status="ACTIVE")
+ self._process_distributed_router_create(context, router_db, r)
+ context.session.add(router_db)
if has_gw_info:
self._update_router_gw_info(context, router_db['id'], gw_info)
- return self._make_router_dict(router_db)
+ router = self._make_router_dict(router_db)
+ return router
def update_router(self, context, router_id, router):
# Either nexthop is updated or should be kept as it was before
LOG.warning(_("Found %s logical routers not bound "
"to Neutron routers. Neutron and NVP are "
"potentially out of sync"), len(nvp_lrouters))
-
- return [self._make_router_dict(router, fields)
- for router in routers]
+ return [self._make_router_dict(router, fields) for router in routers]
def add_router_interface(self, context, router_id, interface_info):
# When adding interface by port_id we need to create the
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Nicira Networks, 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.
+#
+# @author: Salvatore Orlando, Nicira, Inc
+#
+
+from neutron.db import db_base_plugin_v2
+from neutron.extensions import l3
+from neutron.openstack.common import log as logging
+from neutron.plugins.nicira.dbexts import nicira_models
+from neutron.plugins.nicira.extensions import distributedrouter as dist_rtr
+
+LOG = logging.getLogger(__name__)
+
+
+class DistributedRouter_mixin(object):
+ """Mixin class to enable distributed router support."""
+
+ def _extend_router_dict_distributed(self, router_res, router_db):
+ # Avoid setting attribute to None for routers already existing before
+ # the data model was extended with the distributed attribute
+ nsx_attrs = router_db['nsx_attributes']
+ # Return False if nsx attributes are not definied for this
+ # neutron router
+ router_res[dist_rtr.DISTRIBUTED] = (
+ nsx_attrs and nsx_attrs['distributed'] or False)
+
+ def _process_distributed_router_create(
+ self, context, router_db, router_req):
+ """Ensures persistency for the 'distributed' attribute.
+
+ Either creates or fetches the nicira extended attributes
+ record for this router and stores the 'distributed'
+ attribute value.
+ This method should be called from within a transaction, as
+ it does not start a new one.
+ """
+ if not router_db['nsx_attributes']:
+ nsx_attributes = nicira_models.NSXRouterExtAttributes(
+ router_id=router_db['id'],
+ distributed=router_req['distributed'])
+ context.session.add(nsx_attributes)
+ router_db['nsx_attributes'] = nsx_attributes
+ else:
+ # The situation where the record already exists will
+ # be likely once the NSXRouterExtAttributes model
+ # will allow for defining several attributes pertaining
+ # to different extensions
+ router_db['nsx_attributes']['distributed'] = (
+ router_req['distributed'])
+ LOG.debug(_("Distributed router extension successfully processed "
+ "for router:%s"), router_db['id'])
+
+ # Register dict extend functions for ports
+ db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
+ l3.ROUTERS, [_extend_router_dict_distributed])
# under the License.
-from sqlalchemy import Column, Enum, ForeignKey, Integer, String
+from sqlalchemy import Boolean, Column, Enum, ForeignKey, Integer, String
+from sqlalchemy import orm
+from neutron.db import l3_db
from neutron.db.models_v2 import model_base
def __init__(self, network_id):
self.network_id = network_id
+
+
+class NSXRouterExtAttributes(model_base.BASEV2):
+ """Router attributes managed by Nicira plugin extensions."""
+ router_id = Column(String(36),
+ ForeignKey('routers.id', ondelete="CASCADE"),
+ primary_key=True)
+ distributed = Column(Boolean, default=False, nullable=False)
+ # Add a relationship to the Router model in order to instruct
+ # SQLAlchemy to eagerly load this association
+ router = orm.relationship(
+ l3_db.Router,
+ backref=orm.backref("nsx_attributes", lazy='joined',
+ uselist=False, cascade='delete'))
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 Nicira Networks, 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
+
+
+def convert_to_boolean_if_not_none(data):
+ if data is not None:
+ return attributes.convert_to_boolean(data)
+ return data
+
+
+DISTRIBUTED = 'distributed'
+EXTENDED_ATTRIBUTES_2_0 = {
+ 'routers': {
+ DISTRIBUTED: {'allow_post': True, 'allow_put': False,
+ 'convert_to': convert_to_boolean_if_not_none,
+ 'default': attributes.ATTR_NOT_SPECIFIED,
+ 'is_visible': True},
+ }
+}
+
+
+class Distributedrouter(object):
+ """Extension class supporting distributed router."""
+
+ @classmethod
+ def get_name(cls):
+ return "Distributed Router"
+
+ @classmethod
+ def get_alias(cls):
+ return "dist-router"
+
+ @classmethod
+ def get_description(cls):
+ return "Enables configuration of NSX Distributed routers"
+
+ @classmethod
+ def get_namespace(cls):
+ return "http://docs.openstack.org/ext/dist-router/api/v1.0"
+
+ @classmethod
+ def get_updated(cls):
+ return "2013-08-1T10:00:00-00:00"
+
+ def get_required_extensions(self):
+ return ["router"]
+
+ @classmethod
+ def get_resources(cls):
+ """Returns Ext Resources."""
+ return []
+
+ def get_extended_resources(self, version):
+ if version == "2.0":
+ return EXTENDED_ATTRIBUTES_2_0
+ else:
+ return {}
json.dumps(gwservice_obj), cluster=cluster)
-def _prepare_lrouter_body(name, tenant_id, router_type, **kwargs):
+def _prepare_lrouter_body(name, tenant_id, router_type,
+ distributed=None, **kwargs):
body = {
"display_name": _check_and_truncate_name(name),
"tags": [{"tag": tenant_id, "scope": "os_tid"},
},
"type": "LogicalRouterConfig"
}
+ # add the distributed key only if not None (ie: True or False)
+ if distributed is not None:
+ body['distributed'] = distributed
if kwargs:
body["routing_config"].update(kwargs)
return body
-def create_implicit_routing_lrouter(cluster, tenant_id, display_name, nexthop):
- """Create a NVP logical router on the specified cluster.
-
- :param cluster: The target NVP cluster
- :param tenant_id: Identifier of the Openstack tenant for which
- the logical router is being created
- :param display_name: Descriptive name of this logical router
- :param nexthop: External gateway IP address for the logical router
- :raise NvpApiException: if there is a problem while communicating
- with the NVP controller
- """
+def _create_implicit_routing_lrouter(cluster, tenant_id,
+ display_name, nexthop,
+ distributed=None):
implicit_routing_config = {
"default_route_next_hop": {
"gateway_ip_address": nexthop,
lrouter_obj = _prepare_lrouter_body(
display_name, tenant_id,
"SingleDefaultRouteImplicitRoutingConfig",
+ distributed=distributed,
**implicit_routing_config)
return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
json.dumps(lrouter_obj), cluster=cluster)
-def create_explicit_routing_lrouter(cluster, tenant_id,
+def create_implicit_routing_lrouter(cluster, tenant_id,
display_name, nexthop):
+ """Create a NVP logical router on the specified cluster.
+
+ :param cluster: The target NVP cluster
+ :param tenant_id: Identifier of the Openstack tenant for which
+ the logical router is being created
+ :param display_name: Descriptive name of this logical router
+ :param nexthop: External gateway IP address for the logical router
+ :raise NvpApiException: if there is a problem while communicating
+ with the NVP controller
+ """
+ return _create_implicit_routing_lrouter(
+ cluster, tenant_id, display_name, nexthop)
+
+
+def create_implicit_routing_lrouter_with_distribution(
+ cluster, tenant_id, display_name, nexthop, distributed=None):
+ """Create a NVP logical router on the specified cluster.
+
+ This function also allows for creating distributed lrouters
+ :param cluster: The target NVP cluster
+ :param tenant_id: Identifier of the Openstack tenant for which
+ the logical router is being created
+ :param display_name: Descriptive name of this logical router
+ :param nexthop: External gateway IP address for the logical router
+ :param distributed: True for distributed logical routers
+ :raise NvpApiException: if there is a problem while communicating
+ with the NVP controller
+ """
+ return _create_implicit_routing_lrouter(
+ cluster, tenant_id, display_name, nexthop, distributed)
+
+
+def create_explicit_routing_lrouter(cluster, tenant_id,
+ display_name, nexthop,
+ distributed=None):
lrouter_obj = _prepare_lrouter_body(
- display_name, tenant_id, "RoutingTableRoutingConfig")
+ display_name, tenant_id, "RoutingTableRoutingConfig",
+ distributed=distributed)
router = do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
json.dumps(lrouter_obj), cluster=cluster)
default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
'create_lrouter': {
2: {DEFAULT: create_implicit_routing_lrouter, },
3: {DEFAULT: create_implicit_routing_lrouter,
+ 1: create_implicit_routing_lrouter_with_distribution,
2: create_explicit_routing_lrouter, }, },
'update_lrouter': {
2: {DEFAULT: update_implicit_routing_lrouter, },
# See the License for the specific language governing permissions and
# limitations under the License.
-from neutron.common.test_lib import test_config
from neutron.tests.unit.metaplugin.test_metaplugin import setup_metaplugin_conf
from neutron.tests.unit import test_db_plugin as test_plugin
from neutron.tests.unit import test_l3_plugin
_plugin_name = ('neutron.plugins.metaplugin.'
'meta_neutron_plugin.MetaPluginV2')
- def setUp(self):
+ def setUp(self, plugin=None, ext_mgr=None):
+ # NOTE(salv-orlando): The plugin keyword argument is ignored,
+ # as this class will always invoke super with self._plugin_name.
+ # These keyword parameters ensure setUp methods always have the
+ # same signature.
setup_metaplugin_conf()
- ext_mgr = test_l3_plugin.L3TestExtensionManager()
- test_config['extension_manager'] = ext_mgr
- super(MetaPluginV2DBTestCase, self).setUp(self._plugin_name)
+ ext_mgr = ext_mgr or test_l3_plugin.L3TestExtensionManager()
+ super(MetaPluginV2DBTestCase, self).setUp(
+ plugin=self._plugin_name, ext_mgr=ext_mgr)
class TestMetaBasicGet(test_plugin.TestBasicGet,
{
"display_name": "%(display_name)s",
+ %(distributed_json)s
"uuid": "%(uuid)s",
"tags": %(tags_json)s,
"routing_config": {
{
"display_name": "%(display_name)s",
+ %(distributed_json)s
"uuid": "%(uuid)s",
"tags": [
{
'default_route_next_hop')
fake_lrouter['default_next_hop'] = default_nexthop.get(
'gateway_ip_address', '0.0.0.0')
+ # NOTE(salv-orlando): We won't make the Fake NVP API client
+ # aware of NVP version. The long term plan is to replace it
+ # with behavioral mocking of NVP API requests
+ if 'distributed' not in fake_lrouter:
+ fake_lrouter['distributed'] = False
+ distributed_json = ('"distributed": %s,' %
+ str(fake_lrouter['distributed']).lower())
+ fake_lrouter['distributed_json'] = distributed_json
return fake_lrouter
def _add_lrouter(self, body):
from oslo.config import cfg
import webob.exc
+from neutron.api.v2 import attributes
from neutron.common import constants
from neutron.common import exceptions as ntn_exc
import neutron.common.test_lib as test_lib
from neutron import context
from neutron.extensions import l3
+from neutron.extensions import l3_ext_gw_mode
from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings
from neutron.extensions import providernet as pnet
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.dbexts import nicira_db
from neutron.plugins.nicira.dbexts import nicira_qos_db as qos_db
+from neutron.plugins.nicira.extensions import distributedrouter as dist_router
from neutron.plugins.nicira.extensions import nvp_networkgw
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira import NeutronPlugin
from neutron.tests.unit import testlib_api
+from neutron.openstack.common import log
+LOG = log.getLogger(__name__)
+
+
class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
def _create_network(self, fmt, name, admin_state_up,
data = {'network': {'name': name,
'admin_state_up': admin_state_up,
'tenant_id': self._tenant_id}}
- attributes = kwargs
+ attrs = kwargs
if providernet_args:
- attributes.update(providernet_args)
+ attrs.update(providernet_args)
for arg in (('admin_state_up', 'tenant_id', 'shared') +
(arg_list or ())):
# Arg must be present and not empty
'', kwargs['tenant_id'])
return network_req.get_response(self.api)
- def setUp(self):
+ def setUp(self, plugin=None, ext_mgr=None):
test_lib.test_config['config_files'] = [get_fake_conf('nvp.ini.test')]
# mock nvp api client
self.fc = fake_nvpapiclient.FakeClient(STUBS_PATH)
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
- instance = self.mock_nvpapi.start()
+ self.mock_instance = self.mock_nvpapi.start()
def _fake_request(*args, **kwargs):
return self.fc.fake_request(*args, **kwargs)
# Emulate tests against NVP 2.x
- instance.return_value.get_nvp_version.return_value = NVPVersion("2.9")
- instance.return_value.request.side_effect = _fake_request
- super(NiciraPluginV2TestCase, self).setUp(plugin=PLUGIN_NAME)
+ self.mock_instance.return_value.get_nvp_version.return_value = (
+ NVPVersion("2.9"))
+ self.mock_instance.return_value.request.side_effect = _fake_request
+ plugin = plugin or PLUGIN_NAME
+ super(NiciraPluginV2TestCase, self).setUp(plugin=plugin,
+ ext_mgr=ext_mgr)
cfg.CONF.set_override('metadata_mode', None, 'NVP')
self.addCleanup(self.fc.reset_all)
self.addCleanup(self.mock_nvpapi.stop)
self.assertEqual(sg['security_group']['name'], name)
+class TestNiciraL3ExtensionManager(object):
+
+ def get_resources(self):
+ # Simulate extension of L3 attribute map
+ # First apply attribute extensions
+ for key in l3.RESOURCE_ATTRIBUTE_MAP.keys():
+ l3.RESOURCE_ATTRIBUTE_MAP[key].update(
+ l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
+ l3.RESOURCE_ATTRIBUTE_MAP[key].update(
+ dist_router.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
+ # Finally add l3 resources to the global attribute map
+ attributes.RESOURCE_ATTRIBUTE_MAP.update(
+ l3.RESOURCE_ATTRIBUTE_MAP)
+ return l3.L3.get_resources()
+
+ def get_actions(self):
+ return []
+
+ def get_request_extensions(self):
+ return []
+
+
class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBTestCase,
NiciraPluginV2TestCase):
+ def _restore_l3_attribute_map(self):
+ l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk
+
+ def setUp(self):
+ self._l3_attribute_map_bk = {}
+ for item in l3.RESOURCE_ATTRIBUTE_MAP:
+ self._l3_attribute_map_bk[item] = (
+ l3.RESOURCE_ATTRIBUTE_MAP[item].copy())
+ cfg.CONF.set_override('api_extensions_path', NVPEXT_PATH)
+ self.addCleanup(self._restore_l3_attribute_map)
+ super(TestNiciraL3NatTestCase, self).setUp(
+ ext_mgr=TestNiciraL3ExtensionManager())
+
+ def tearDown(self):
+ super(TestNiciraL3NatTestCase, self).tearDown()
+
def _create_l3_ext_network(self, vlan_id=None):
name = 'l3_ext_net'
net_type = NeutronPlugin.NetworkTypes.L3_EXT
def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self):
self._test_router_create_with_gwinfo_and_l3_ext_net(444)
+ def _test_router_create_with_distributed(self, dist_input, dist_expected):
+ self.mock_instance.return_value.get_nvp_version.return_value = (
+ NvpApiClient.NVPVersion('3.1'))
+
+ data = {'tenant_id': 'whatever'}
+ data['name'] = 'router1'
+ data['distributed'] = dist_input
+ router_req = self.new_create_request(
+ 'routers', {'router': data}, self.fmt)
+ try:
+ res = router_req.get_response(self.ext_api)
+ router = self.deserialize(self.fmt, res)
+ self.assertIn('distributed', router['router'])
+ self.assertEqual(dist_expected,
+ router['router']['distributed'])
+ finally:
+ self._delete('routers', router['router']['id'])
+
+ def test_router_create_distributed(self):
+ self._test_router_create_with_distributed(True, True)
+
+ def test_router_create_not_distributed(self):
+ self._test_router_create_with_distributed(False, False)
+
+ def test_router_create_distributed_unspecified(self):
+ self._test_router_create_with_distributed(None, False)
+
def test_router_create_nvp_error_returns_500(self, vlan_id=None):
with mock.patch.object(nvplib,
'create_router_lport',
res = router_req.get_response(self.ext_api)
self.assertEqual(500, res.status_int)
+ def test_router_add_gateway_invalid_network_returns_404(self):
+ # NOTE(salv-orlando): This unit test has been overriden
+ # as the nicira plugin support the ext_gw_mode extension
+ # which mandates a uuid for the external network identifier
+ with self.router() as r:
+ self._add_external_gateway_to_router(
+ r['router']['id'],
+ uuidutils.generate_uuid(),
+ expected_code=webob.exc.HTTPNotFound.code)
+
def _test_router_update_gateway_on_l3_ext_net(self, vlan_id=None):
with self.router() as r:
with self.subnet() as s1:
pass
-class NiciraNeutronNVPOutOfSync(test_l3_plugin.L3NatTestCaseBase,
- NiciraPluginV2TestCase):
+class NiciraNeutronNVPOutOfSync(NiciraPluginV2TestCase,
+ test_l3_plugin.L3NatTestCaseBase):
+
+ def setUp(self):
+ super(NiciraNeutronNVPOutOfSync, self).setUp()
def test_delete_network_not_in_nvp(self):
res = self._create_network('json', 'net1', True)
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
instance = self.mock_nvpapi.start()
instance.return_value.login.return_value = "the_cookie"
- fake_version = getattr(self, 'fake_version', "2.9")
+ fake_version = getattr(self, 'fake_version', "3.0")
instance.return_value.get_nvp_version.return_value = (
NvpApiClient.NVPVersion(fake_version))
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
instance = self.mock_nvpapi.start()
instance.return_value.login.return_value = "the_cookie"
- # Choose 2.9, but the version is irrelevant for the aim of
+ # Choose 3.0, but the version is irrelevant for the aim of
# these tests as calls are throwing up errors anyway
- self.fake_version = NvpApiClient.NVPVersion('2.9')
- instance.return_value.get_nvp_version.return_value = self.fake_version
+ fake_version = getattr(self, 'fake_version', "3.0")
+ instance.return_value.get_nvp_version.return_value = (
+ NvpApiClient.NVPVersion(fake_version))
def _faulty_request(*args, **kwargs):
raise nvplib.NvpApiClient.NvpApiException
expected_uuid,
expected_display_name,
expected_nexthop,
- expected_tenant_id):
+ expected_tenant_id,
+ expected_distributed=None):
self.assertEqual(res_lrouter['uuid'], expected_uuid)
nexthop = (res_lrouter['routing_config']
['default_route_next_hop']['gateway_ip_address'])
self.assertIn('os_tid', router_tags)
self.assertEqual(res_lrouter['display_name'], expected_display_name)
self.assertEqual(expected_tenant_id, router_tags['os_tid'])
+ if expected_distributed is not None:
+ self.assertEqual(expected_distributed,
+ res_lrouter['distributed'])
def test_get_lrouters(self):
lrouter_uuids = [nvplib.create_lrouter(
for router in routers:
self.assertIn(router['uuid'], lrouter_uuids)
- def test_create_and_get_lrouter(self):
- lrouter = nvplib.create_lrouter(self.fake_cluster,
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- res_lrouter = nvplib.get_lrouter(self.fake_cluster,
- lrouter['uuid'])
- self._verify_lrouter(res_lrouter, lrouter['uuid'],
+ def _create_lrouter(self, version, distributed=None):
+ with mock.patch.object(
+ self.fake_cluster.api_client, 'get_nvp_version',
+ return_value=NvpApiClient.NVPVersion(version)):
+ lrouter = nvplib.create_lrouter(
+ self.fake_cluster, 'pippo', 'fake-lrouter',
+ '10.0.0.1', distributed=distributed)
+ return nvplib.get_lrouter(self.fake_cluster,
+ lrouter['uuid'])
+
+ def test_create_and_get_lrouter_v30(self):
+ res_lrouter = self._create_lrouter('3.0')
+ self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo')
+ def test_create_and_get_lrouter_v31_centralized(self):
+ res_lrouter = self._create_lrouter('3.1', distributed=False)
+ self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
+ 'fake-lrouter', '10.0.0.1', 'pippo',
+ expected_distributed=False)
+
+ def test_create_and_get_lrouter_v31_distributed(self):
+ res_lrouter = self._create_lrouter('3.1', distributed=True)
+ self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
+ 'fake-lrouter', '10.0.0.1', 'pippo',
+ expected_distributed=True)
+
def test_create_and_get_lrouter_name_exceeds_40chars(self):
display_name = '*' * 50
lrouter = nvplib.create_lrouter(self.fake_cluster,
class ExtGwModeTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
test_l3_plugin.L3NatTestCaseMixin):
- def setUp(self, plugin=None):
+ def setUp(self, plugin=None, ext_mgr=None):
# Store l3 resource attribute map as it will be updated
self._l3_attribute_map_bk = {}
for item in l3.RESOURCE_ATTRIBUTE_MAP:
'neutron.tests.unit.test_extension_ext_gw_mode.TestDbPlugin')
# for these tests we need to enable overlapping ips
cfg.CONF.set_default('allow_overlapping_ips', True)
+ ext_mgr = ext_mgr or TestExtensionManager()
super(ExtGwModeTestCase, self).setUp(plugin=plugin,
- ext_mgr=TestExtensionManager())
+ ext_mgr=ext_mgr)
self.addCleanup(self.restore_l3_attribute_map)
def restore_l3_attribute_map(self):
class L3NatTestCaseBase(L3NatTestCaseMixin,
test_db_plugin.NeutronDbPluginV2TestCase):
- def setUp(self):
+ def setUp(self, plugin=None, ext_mgr=None):
test_config['plugin_name_v2'] = (
'neutron.tests.unit.test_l3_plugin.TestL3NatPlugin')
# for these tests we need to enable overlapping ips
cfg.CONF.set_default('allow_overlapping_ips', True)
- ext_mgr = L3TestExtensionManager()
- test_config['extension_manager'] = ext_mgr
- super(L3NatTestCaseBase, self).setUp()
+ ext_mgr = ext_mgr or L3TestExtensionManager()
+ super(L3NatTestCaseBase, self).setUp(
+ plugin=plugin, ext_mgr=ext_mgr)
# Set to None to reload the drivers
notifier_api._drivers = None