Support for NVP distributed router
Blueprint nvp-distributed-router This patch adds support for NVP distributed logical routers adding a simple attribute extension. The default router type can be controlled used the default_router_type option in the nvp section of neutron configuration. In order to ensure backward compatibility, pre-existing routers will be treated as centralized routers. Change-Id: Iaab9ffb6071c93990be711ebb56c212230544a7a
This commit is contained in:
parent
58cd00cd1f
commit
634fd1d23f
@ -167,7 +167,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
context.session.add(router_db)
|
context.session.add(router_db)
|
||||||
if has_gw_info:
|
if has_gw_info:
|
||||||
self._update_router_gw_info(context, router_db['id'], 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):
|
def update_router(self, context, id, router):
|
||||||
r = router['router']
|
r = router['router']
|
||||||
|
@ -35,8 +35,9 @@ setattr(l3_db.Router, 'enable_snat',
|
|||||||
class L3_NAT_db_mixin(l3_db.L3_NAT_db_mixin):
|
class L3_NAT_db_mixin(l3_db.L3_NAT_db_mixin):
|
||||||
"""Mixin class to add configurable gateway modes."""
|
"""Mixin class to add configurable gateway modes."""
|
||||||
|
|
||||||
def _make_router_dict(self, router, fields=None):
|
def _make_router_dict(self, router, fields=None, process_extensions=True):
|
||||||
res = super(L3_NAT_db_mixin, self)._make_router_dict(router)
|
res = super(L3_NAT_db_mixin, self)._make_router_dict(
|
||||||
|
router, process_extensions=process_extensions)
|
||||||
if router['gw_port_id']:
|
if router['gw_port_id']:
|
||||||
nw_id = router.gw_port['network_id']
|
nw_id = router.gw_port['network_id']
|
||||||
res[EXTERNAL_GW_INFO] = {'network_id': nw_id,
|
res[EXTERNAL_GW_INFO] = {'network_id': nw_id,
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
# 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')
|
@ -64,6 +64,7 @@ from neutron.plugins.nicira.common import config # noqa
|
|||||||
from neutron.plugins.nicira.common import exceptions as nvp_exc
|
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 metadata_access as nvp_meta
|
||||||
from neutron.plugins.nicira.common import securitygroups as nvp_sec
|
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 maclearning as mac_db
|
||||||
from neutron.plugins.nicira.dbexts import nicira_db
|
from neutron.plugins.nicira.dbexts import nicira_db
|
||||||
from neutron.plugins.nicira.dbexts import nicira_networkgw_db as networkgw_db
|
from neutron.plugins.nicira.dbexts import nicira_networkgw_db as networkgw_db
|
||||||
@ -134,6 +135,7 @@ class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
|||||||
class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
|
dist_rtr.DistributedRouter_mixin,
|
||||||
portbindings_db.PortBindingMixin,
|
portbindings_db.PortBindingMixin,
|
||||||
portsecurity_db.PortSecurityDbMixin,
|
portsecurity_db.PortSecurityDbMixin,
|
||||||
securitygroups_db.SecurityGroupDbMixin,
|
securitygroups_db.SecurityGroupDbMixin,
|
||||||
@ -152,6 +154,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
supported_extension_aliases = ["agent",
|
supported_extension_aliases = ["agent",
|
||||||
"binding",
|
"binding",
|
||||||
"dhcp_agent_scheduler",
|
"dhcp_agent_scheduler",
|
||||||
|
"dist-router",
|
||||||
"ext-gw-mode",
|
"ext-gw-mode",
|
||||||
"extraroute",
|
"extraroute",
|
||||||
"mac-learning",
|
"mac-learning",
|
||||||
@ -162,7 +165,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"provider",
|
"provider",
|
||||||
"quotas",
|
"quotas",
|
||||||
"router",
|
"router",
|
||||||
"security-group", ]
|
"security-group"]
|
||||||
|
|
||||||
__native_bulk_support = True
|
__native_bulk_support = True
|
||||||
|
|
||||||
@ -171,6 +174,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def __init__(self):
|
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
|
# Routines for managing logical ports in NVP
|
||||||
self._port_drivers = {
|
self._port_drivers = {
|
||||||
'create': {l3_db.DEVICE_OWNER_ROUTER_GW:
|
'create': {l3_db.DEVICE_OWNER_ROUTER_GW:
|
||||||
@ -1624,11 +1629,16 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
if ext_net.subnets:
|
if ext_net.subnets:
|
||||||
ext_subnet = ext_net.subnets[0]
|
ext_subnet = ext_net.subnets[0]
|
||||||
nexthop = ext_subnet.gateway_ip
|
nexthop = ext_subnet.gateway_ip
|
||||||
lrouter = nvplib.create_lrouter(self.cluster, tenant_id,
|
distributed = r.get('distributed')
|
||||||
router['router']['name'],
|
lrouter = nvplib.create_lrouter(
|
||||||
nexthop)
|
self.cluster, tenant_id, router['router']['name'], nexthop,
|
||||||
|
distributed=attr.is_attr_set(distributed) and distributed)
|
||||||
# Use NVP identfier for Neutron resource
|
# 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:
|
except NvpApiClient.NvpApiException:
|
||||||
raise nvp_exc.NvpPluginException(
|
raise nvp_exc.NvpPluginException(
|
||||||
err_msg=_("Unable to create logical router on NVP Platform"))
|
err_msg=_("Unable to create logical router on NVP Platform"))
|
||||||
@ -1652,15 +1662,20 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
err_msg=_("Unable to create router %s") % r['name'])
|
err_msg=_("Unable to create router %s") % r['name'])
|
||||||
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
router_db = l3_db.Router(id=lrouter['uuid'],
|
# Transaction nesting is needed to avoid foreign key violations
|
||||||
tenant_id=tenant_id,
|
# when processing the service provider binding
|
||||||
name=r['name'],
|
with context.session.begin(subtransactions=True):
|
||||||
admin_state_up=r['admin_state_up'],
|
router_db = l3_db.Router(id=lrouter['uuid'],
|
||||||
status="ACTIVE")
|
tenant_id=tenant_id,
|
||||||
context.session.add(router_db)
|
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:
|
if has_gw_info:
|
||||||
self._update_router_gw_info(context, router_db['id'], 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):
|
def update_router(self, context, router_id, router):
|
||||||
# Either nexthop is updated or should be kept as it was before
|
# Either nexthop is updated or should be kept as it was before
|
||||||
@ -1816,9 +1831,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
LOG.warning(_("Found %s logical routers not bound "
|
LOG.warning(_("Found %s logical routers not bound "
|
||||||
"to Neutron routers. Neutron and NVP are "
|
"to Neutron routers. Neutron and NVP are "
|
||||||
"potentially out of sync"), len(nvp_lrouters))
|
"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):
|
def add_router_interface(self, context, router_id, interface_info):
|
||||||
# When adding interface by port_id we need to create the
|
# When adding interface by port_id we need to create the
|
||||||
|
69
neutron/plugins/nicira/dbexts/distributedrouter.py
Normal file
69
neutron/plugins/nicira/dbexts/distributedrouter.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# 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])
|
@ -16,8 +16,10 @@
|
|||||||
# under the License.
|
# 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
|
from neutron.db.models_v2 import model_base
|
||||||
|
|
||||||
|
|
||||||
@ -79,3 +81,17 @@ class MultiProviderNetworks(model_base.BASEV2):
|
|||||||
|
|
||||||
def __init__(self, network_id):
|
def __init__(self, network_id):
|
||||||
self.network_id = 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'))
|
||||||
|
73
neutron/plugins/nicira/extensions/distributedrouter.py
Normal file
73
neutron/plugins/nicira/extensions/distributedrouter.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# 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 {}
|
@ -274,7 +274,8 @@ def create_l2_gw_service(cluster, tenant_id, display_name, devices):
|
|||||||
json.dumps(gwservice_obj), cluster=cluster)
|
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 = {
|
body = {
|
||||||
"display_name": _check_and_truncate_name(name),
|
"display_name": _check_and_truncate_name(name),
|
||||||
"tags": [{"tag": tenant_id, "scope": "os_tid"},
|
"tags": [{"tag": tenant_id, "scope": "os_tid"},
|
||||||
@ -284,12 +285,34 @@ def _prepare_lrouter_body(name, tenant_id, router_type, **kwargs):
|
|||||||
},
|
},
|
||||||
"type": "LogicalRouterConfig"
|
"type": "LogicalRouterConfig"
|
||||||
}
|
}
|
||||||
|
# add the distributed key only if not None (ie: True or False)
|
||||||
|
if distributed is not None:
|
||||||
|
body['distributed'] = distributed
|
||||||
if kwargs:
|
if kwargs:
|
||||||
body["routing_config"].update(kwargs)
|
body["routing_config"].update(kwargs)
|
||||||
return body
|
return body
|
||||||
|
|
||||||
|
|
||||||
def create_implicit_routing_lrouter(cluster, tenant_id, display_name, nexthop):
|
def _create_implicit_routing_lrouter(cluster, tenant_id,
|
||||||
|
display_name, nexthop,
|
||||||
|
distributed=None):
|
||||||
|
implicit_routing_config = {
|
||||||
|
"default_route_next_hop": {
|
||||||
|
"gateway_ip_address": nexthop,
|
||||||
|
"type": "RouterNextHop"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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_implicit_routing_lrouter(cluster, tenant_id,
|
||||||
|
display_name, nexthop):
|
||||||
"""Create a NVP logical router on the specified cluster.
|
"""Create a NVP logical router on the specified cluster.
|
||||||
|
|
||||||
:param cluster: The target NVP cluster
|
:param cluster: The target NVP cluster
|
||||||
@ -300,24 +323,34 @@ def create_implicit_routing_lrouter(cluster, tenant_id, display_name, nexthop):
|
|||||||
:raise NvpApiException: if there is a problem while communicating
|
:raise NvpApiException: if there is a problem while communicating
|
||||||
with the NVP controller
|
with the NVP controller
|
||||||
"""
|
"""
|
||||||
implicit_routing_config = {
|
return _create_implicit_routing_lrouter(
|
||||||
"default_route_next_hop": {
|
cluster, tenant_id, display_name, nexthop)
|
||||||
"gateway_ip_address": nexthop,
|
|
||||||
"type": "RouterNextHop"
|
|
||||||
},
|
def create_implicit_routing_lrouter_with_distribution(
|
||||||
}
|
cluster, tenant_id, display_name, nexthop, distributed=None):
|
||||||
lrouter_obj = _prepare_lrouter_body(
|
"""Create a NVP logical router on the specified cluster.
|
||||||
display_name, tenant_id,
|
|
||||||
"SingleDefaultRouteImplicitRoutingConfig",
|
This function also allows for creating distributed lrouters
|
||||||
**implicit_routing_config)
|
:param cluster: The target NVP cluster
|
||||||
return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
|
:param tenant_id: Identifier of the Openstack tenant for which
|
||||||
json.dumps(lrouter_obj), cluster=cluster)
|
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,
|
def create_explicit_routing_lrouter(cluster, tenant_id,
|
||||||
display_name, nexthop):
|
display_name, nexthop,
|
||||||
|
distributed=None):
|
||||||
lrouter_obj = _prepare_lrouter_body(
|
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),
|
router = do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
|
||||||
json.dumps(lrouter_obj), cluster=cluster)
|
json.dumps(lrouter_obj), cluster=cluster)
|
||||||
default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
|
default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
|
||||||
@ -1191,6 +1224,7 @@ NVPLIB_FUNC_DICT = {
|
|||||||
'create_lrouter': {
|
'create_lrouter': {
|
||||||
2: {DEFAULT: create_implicit_routing_lrouter, },
|
2: {DEFAULT: create_implicit_routing_lrouter, },
|
||||||
3: {DEFAULT: create_implicit_routing_lrouter,
|
3: {DEFAULT: create_implicit_routing_lrouter,
|
||||||
|
1: create_implicit_routing_lrouter_with_distribution,
|
||||||
2: create_explicit_routing_lrouter, }, },
|
2: create_explicit_routing_lrouter, }, },
|
||||||
'update_lrouter': {
|
'update_lrouter': {
|
||||||
2: {DEFAULT: update_implicit_routing_lrouter, },
|
2: {DEFAULT: update_implicit_routing_lrouter, },
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# 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.metaplugin.test_metaplugin import setup_metaplugin_conf
|
||||||
from neutron.tests.unit import test_db_plugin as test_plugin
|
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||||
from neutron.tests.unit import test_l3_plugin
|
from neutron.tests.unit import test_l3_plugin
|
||||||
@ -24,11 +23,15 @@ class MetaPluginV2DBTestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
_plugin_name = ('neutron.plugins.metaplugin.'
|
_plugin_name = ('neutron.plugins.metaplugin.'
|
||||||
'meta_neutron_plugin.MetaPluginV2')
|
'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()
|
setup_metaplugin_conf()
|
||||||
ext_mgr = test_l3_plugin.L3TestExtensionManager()
|
ext_mgr = ext_mgr or test_l3_plugin.L3TestExtensionManager()
|
||||||
test_config['extension_manager'] = ext_mgr
|
super(MetaPluginV2DBTestCase, self).setUp(
|
||||||
super(MetaPluginV2DBTestCase, self).setUp(self._plugin_name)
|
plugin=self._plugin_name, ext_mgr=ext_mgr)
|
||||||
|
|
||||||
|
|
||||||
class TestMetaBasicGet(test_plugin.TestBasicGet,
|
class TestMetaBasicGet(test_plugin.TestBasicGet,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"display_name": "%(display_name)s",
|
"display_name": "%(display_name)s",
|
||||||
|
%(distributed_json)s
|
||||||
"uuid": "%(uuid)s",
|
"uuid": "%(uuid)s",
|
||||||
"tags": %(tags_json)s,
|
"tags": %(tags_json)s,
|
||||||
"routing_config": {
|
"routing_config": {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"display_name": "%(display_name)s",
|
"display_name": "%(display_name)s",
|
||||||
|
%(distributed_json)s
|
||||||
"uuid": "%(uuid)s",
|
"uuid": "%(uuid)s",
|
||||||
"tags": [
|
"tags": [
|
||||||
{
|
{
|
||||||
|
@ -168,6 +168,14 @@ class FakeClient:
|
|||||||
'default_route_next_hop')
|
'default_route_next_hop')
|
||||||
fake_lrouter['default_next_hop'] = default_nexthop.get(
|
fake_lrouter['default_next_hop'] = default_nexthop.get(
|
||||||
'gateway_ip_address', '0.0.0.0')
|
'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
|
return fake_lrouter
|
||||||
|
|
||||||
def _add_lrouter(self, body):
|
def _add_lrouter(self, body):
|
||||||
|
@ -20,11 +20,13 @@ import netaddr
|
|||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions as ntn_exc
|
from neutron.common import exceptions as ntn_exc
|
||||||
import neutron.common.test_lib as test_lib
|
import neutron.common.test_lib as test_lib
|
||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron.extensions import l3
|
from neutron.extensions import l3
|
||||||
|
from neutron.extensions import l3_ext_gw_mode
|
||||||
from neutron.extensions import multiprovidernet as mpnet
|
from neutron.extensions import multiprovidernet as mpnet
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron.extensions import providernet as pnet
|
from neutron.extensions import providernet as pnet
|
||||||
@ -34,6 +36,7 @@ from neutron.openstack.common import uuidutils
|
|||||||
from neutron.plugins.nicira.common import exceptions as nvp_exc
|
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_db
|
||||||
from neutron.plugins.nicira.dbexts import nicira_qos_db as qos_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_networkgw
|
||||||
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
|
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
|
||||||
from neutron.plugins.nicira import NeutronPlugin
|
from neutron.plugins.nicira import NeutronPlugin
|
||||||
@ -57,6 +60,10 @@ import neutron.tests.unit.test_l3_plugin as test_l3_plugin
|
|||||||
from neutron.tests.unit import testlib_api
|
from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
|
|
||||||
|
from neutron.openstack.common import log
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
|
||||||
def _create_network(self, fmt, name, admin_state_up,
|
def _create_network(self, fmt, name, admin_state_up,
|
||||||
@ -64,9 +71,9 @@ class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
data = {'network': {'name': name,
|
data = {'network': {'name': name,
|
||||||
'admin_state_up': admin_state_up,
|
'admin_state_up': admin_state_up,
|
||||||
'tenant_id': self._tenant_id}}
|
'tenant_id': self._tenant_id}}
|
||||||
attributes = kwargs
|
attrs = kwargs
|
||||||
if providernet_args:
|
if providernet_args:
|
||||||
attributes.update(providernet_args)
|
attrs.update(providernet_args)
|
||||||
for arg in (('admin_state_up', 'tenant_id', 'shared') +
|
for arg in (('admin_state_up', 'tenant_id', 'shared') +
|
||||||
(arg_list or ())):
|
(arg_list or ())):
|
||||||
# Arg must be present and not empty
|
# Arg must be present and not empty
|
||||||
@ -79,20 +86,23 @@ class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
'', kwargs['tenant_id'])
|
'', kwargs['tenant_id'])
|
||||||
return network_req.get_response(self.api)
|
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')]
|
test_lib.test_config['config_files'] = [get_fake_conf('nvp.ini.test')]
|
||||||
# mock nvp api client
|
# mock nvp api client
|
||||||
self.fc = fake_nvpapiclient.FakeClient(STUBS_PATH)
|
self.fc = fake_nvpapiclient.FakeClient(STUBS_PATH)
|
||||||
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
|
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):
|
def _fake_request(*args, **kwargs):
|
||||||
return self.fc.fake_request(*args, **kwargs)
|
return self.fc.fake_request(*args, **kwargs)
|
||||||
|
|
||||||
# Emulate tests against NVP 2.x
|
# Emulate tests against NVP 2.x
|
||||||
instance.return_value.get_nvp_version.return_value = NVPVersion("2.9")
|
self.mock_instance.return_value.get_nvp_version.return_value = (
|
||||||
instance.return_value.request.side_effect = _fake_request
|
NVPVersion("2.9"))
|
||||||
super(NiciraPluginV2TestCase, self).setUp(plugin=PLUGIN_NAME)
|
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')
|
cfg.CONF.set_override('metadata_mode', None, 'NVP')
|
||||||
self.addCleanup(self.fc.reset_all)
|
self.addCleanup(self.fc.reset_all)
|
||||||
self.addCleanup(self.mock_nvpapi.stop)
|
self.addCleanup(self.mock_nvpapi.stop)
|
||||||
@ -361,9 +371,47 @@ class TestNiciraSecurityGroup(ext_sg.TestSecurityGroups,
|
|||||||
self.assertEqual(sg['security_group']['name'], name)
|
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,
|
class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBTestCase,
|
||||||
NiciraPluginV2TestCase):
|
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):
|
def _create_l3_ext_network(self, vlan_id=None):
|
||||||
name = 'l3_ext_net'
|
name = 'l3_ext_net'
|
||||||
net_type = NeutronPlugin.NetworkTypes.L3_EXT
|
net_type = NeutronPlugin.NetworkTypes.L3_EXT
|
||||||
@ -432,6 +480,33 @@ class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBTestCase,
|
|||||||
def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self):
|
def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self):
|
||||||
self._test_router_create_with_gwinfo_and_l3_ext_net(444)
|
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):
|
def test_router_create_nvp_error_returns_500(self, vlan_id=None):
|
||||||
with mock.patch.object(nvplib,
|
with mock.patch.object(nvplib,
|
||||||
'create_router_lport',
|
'create_router_lport',
|
||||||
@ -447,6 +522,16 @@ class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBTestCase,
|
|||||||
res = router_req.get_response(self.ext_api)
|
res = router_req.get_response(self.ext_api)
|
||||||
self.assertEqual(500, res.status_int)
|
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):
|
def _test_router_update_gateway_on_l3_ext_net(self, vlan_id=None):
|
||||||
with self.router() as r:
|
with self.router() as r:
|
||||||
with self.subnet() as s1:
|
with self.subnet() as s1:
|
||||||
@ -1004,8 +1089,11 @@ class NiciraExtGwModeTestCase(NiciraPluginV2TestCase,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NiciraNeutronNVPOutOfSync(test_l3_plugin.L3NatTestCaseBase,
|
class NiciraNeutronNVPOutOfSync(NiciraPluginV2TestCase,
|
||||||
NiciraPluginV2TestCase):
|
test_l3_plugin.L3NatTestCaseBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(NiciraNeutronNVPOutOfSync, self).setUp()
|
||||||
|
|
||||||
def test_delete_network_not_in_nvp(self):
|
def test_delete_network_not_in_nvp(self):
|
||||||
res = self._create_network('json', 'net1', True)
|
res = self._create_network('json', 'net1', True)
|
||||||
|
@ -42,7 +42,7 @@ class NvplibTestCase(base.BaseTestCase):
|
|||||||
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
|
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
|
||||||
instance = self.mock_nvpapi.start()
|
instance = self.mock_nvpapi.start()
|
||||||
instance.return_value.login.return_value = "the_cookie"
|
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 = (
|
instance.return_value.get_nvp_version.return_value = (
|
||||||
NvpApiClient.NVPVersion(fake_version))
|
NvpApiClient.NVPVersion(fake_version))
|
||||||
|
|
||||||
@ -106,10 +106,11 @@ class NvplibNegativeTests(base.BaseTestCase):
|
|||||||
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
|
self.mock_nvpapi = mock.patch(NVPAPI_NAME, autospec=True)
|
||||||
instance = self.mock_nvpapi.start()
|
instance = self.mock_nvpapi.start()
|
||||||
instance.return_value.login.return_value = "the_cookie"
|
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
|
# these tests as calls are throwing up errors anyway
|
||||||
self.fake_version = NvpApiClient.NVPVersion('2.9')
|
fake_version = getattr(self, 'fake_version', "3.0")
|
||||||
instance.return_value.get_nvp_version.return_value = self.fake_version
|
instance.return_value.get_nvp_version.return_value = (
|
||||||
|
NvpApiClient.NVPVersion(fake_version))
|
||||||
|
|
||||||
def _faulty_request(*args, **kwargs):
|
def _faulty_request(*args, **kwargs):
|
||||||
raise nvplib.NvpApiClient.NvpApiException
|
raise nvplib.NvpApiClient.NvpApiException
|
||||||
@ -572,7 +573,8 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
expected_uuid,
|
expected_uuid,
|
||||||
expected_display_name,
|
expected_display_name,
|
||||||
expected_nexthop,
|
expected_nexthop,
|
||||||
expected_tenant_id):
|
expected_tenant_id,
|
||||||
|
expected_distributed=None):
|
||||||
self.assertEqual(res_lrouter['uuid'], expected_uuid)
|
self.assertEqual(res_lrouter['uuid'], expected_uuid)
|
||||||
nexthop = (res_lrouter['routing_config']
|
nexthop = (res_lrouter['routing_config']
|
||||||
['default_route_next_hop']['gateway_ip_address'])
|
['default_route_next_hop']['gateway_ip_address'])
|
||||||
@ -581,6 +583,9 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
self.assertIn('os_tid', router_tags)
|
self.assertIn('os_tid', router_tags)
|
||||||
self.assertEqual(res_lrouter['display_name'], expected_display_name)
|
self.assertEqual(res_lrouter['display_name'], expected_display_name)
|
||||||
self.assertEqual(expected_tenant_id, router_tags['os_tid'])
|
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):
|
def test_get_lrouters(self):
|
||||||
lrouter_uuids = [nvplib.create_lrouter(
|
lrouter_uuids = [nvplib.create_lrouter(
|
||||||
@ -590,16 +595,33 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
for router in routers:
|
for router in routers:
|
||||||
self.assertIn(router['uuid'], lrouter_uuids)
|
self.assertIn(router['uuid'], lrouter_uuids)
|
||||||
|
|
||||||
def test_create_and_get_lrouter(self):
|
def _create_lrouter(self, version, distributed=None):
|
||||||
lrouter = nvplib.create_lrouter(self.fake_cluster,
|
with mock.patch.object(
|
||||||
'pippo',
|
self.fake_cluster.api_client, 'get_nvp_version',
|
||||||
'fake-lrouter',
|
return_value=NvpApiClient.NVPVersion(version)):
|
||||||
'10.0.0.1')
|
lrouter = nvplib.create_lrouter(
|
||||||
res_lrouter = nvplib.get_lrouter(self.fake_cluster,
|
self.fake_cluster, 'pippo', 'fake-lrouter',
|
||||||
lrouter['uuid'])
|
'10.0.0.1', distributed=distributed)
|
||||||
self._verify_lrouter(res_lrouter, lrouter['uuid'],
|
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')
|
'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):
|
def test_create_and_get_lrouter_name_exceeds_40chars(self):
|
||||||
display_name = '*' * 50
|
display_name = '*' * 50
|
||||||
lrouter = nvplib.create_lrouter(self.fake_cluster,
|
lrouter = nvplib.create_lrouter(self.fake_cluster,
|
||||||
|
@ -300,7 +300,7 @@ class TestL3GwModeMixin(base.BaseTestCase):
|
|||||||
class ExtGwModeTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
|
class ExtGwModeTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
|
||||||
test_l3_plugin.L3NatTestCaseMixin):
|
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
|
# Store l3 resource attribute map as it will be updated
|
||||||
self._l3_attribute_map_bk = {}
|
self._l3_attribute_map_bk = {}
|
||||||
for item in l3.RESOURCE_ATTRIBUTE_MAP:
|
for item in l3.RESOURCE_ATTRIBUTE_MAP:
|
||||||
@ -310,8 +310,9 @@ class ExtGwModeTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
|
|||||||
'neutron.tests.unit.test_extension_ext_gw_mode.TestDbPlugin')
|
'neutron.tests.unit.test_extension_ext_gw_mode.TestDbPlugin')
|
||||||
# for these tests we need to enable overlapping ips
|
# for these tests we need to enable overlapping ips
|
||||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
ext_mgr = ext_mgr or TestExtensionManager()
|
||||||
super(ExtGwModeTestCase, self).setUp(plugin=plugin,
|
super(ExtGwModeTestCase, self).setUp(plugin=plugin,
|
||||||
ext_mgr=TestExtensionManager())
|
ext_mgr=ext_mgr)
|
||||||
self.addCleanup(self.restore_l3_attribute_map)
|
self.addCleanup(self.restore_l3_attribute_map)
|
||||||
|
|
||||||
def restore_l3_attribute_map(self):
|
def restore_l3_attribute_map(self):
|
||||||
|
@ -481,14 +481,14 @@ class L3NatTestCaseMixin(object):
|
|||||||
class L3NatTestCaseBase(L3NatTestCaseMixin,
|
class L3NatTestCaseBase(L3NatTestCaseMixin,
|
||||||
test_db_plugin.NeutronDbPluginV2TestCase):
|
test_db_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self, plugin=None, ext_mgr=None):
|
||||||
test_config['plugin_name_v2'] = (
|
test_config['plugin_name_v2'] = (
|
||||||
'neutron.tests.unit.test_l3_plugin.TestL3NatPlugin')
|
'neutron.tests.unit.test_l3_plugin.TestL3NatPlugin')
|
||||||
# for these tests we need to enable overlapping ips
|
# for these tests we need to enable overlapping ips
|
||||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
ext_mgr = L3TestExtensionManager()
|
ext_mgr = ext_mgr or L3TestExtensionManager()
|
||||||
test_config['extension_manager'] = ext_mgr
|
super(L3NatTestCaseBase, self).setUp(
|
||||||
super(L3NatTestCaseBase, self).setUp()
|
plugin=plugin, ext_mgr=ext_mgr)
|
||||||
|
|
||||||
# Set to None to reload the drivers
|
# Set to None to reload the drivers
|
||||||
notifier_api._drivers = None
|
notifier_api._drivers = None
|
||||||
|
Loading…
Reference in New Issue
Block a user