NSXv3: Add backend driver for Layer 2 gateway

This patch adds the backend driver to support Layer 2 gateway
API calls for NSXv3.

Change-Id: Iec1e143115579cca6c8158188217ead4209959bd
Partial-bug: #1481087
This commit is contained in:
Abhishek Raut 2015-08-06 12:09:06 -07:00
parent 6c6a539de7
commit 06363890ee
17 changed files with 523 additions and 15 deletions

View File

@ -106,6 +106,9 @@ function neutron_plugin_configure_service {
else
die $LINENO "The VMware NSX plugin needs at least an NSX controller."
fi
if [[ "$NSX_L2GW_DRIVER" != "" ]]; then
iniset /$Q_PLUGIN_CONF_FILE nsx nsx_l2gw_driver $NSX_L2GW_DRIVER
fi
_nsxv3_ini_set default_tier0_router_uuid $DEFAULT_TIER0_ROUTER_UUID
_nsxv3_ini_set nsx_manager $NSX_MANAGER "The VMWare NSX plugin needs a NSX manager."
_nsxv3_ini_set nsx_user $NSX_USER

View File

@ -225,6 +225,10 @@
# "service".
# replication_mode = service
# Specify the class path for the Layer 2 gateway backend driver(i.e. NSXv3/NSX-V).
# This field will be used when a L2 Gateway service plugin is configured.
# nsx_l2gw_driver = vmware_nsx.neutron.services.l2gateway.nsx_v3_driver.NsxV3Driver
[nsx_sync]
# Interval in seconds between runs of the status synchronization task.
# The plugin will aim at resynchronizing operational status for all
@ -327,3 +331,11 @@
# UUID of the default tier0 router that will be used for connecting to
# tier1 logical routers and configuring external network
# default_tier0_router_uuid = 412983fd-9016-45e5-93f2-48ba2a931225
# UUID of the default NSX bridge cluster that will be used to perform
# L2 gateway bridging between VXLAN and VLAN networks. It is an optional
# field. If default bridge cluster UUID is not specified, admin will have to
# manually create a L2 gateway corresponding to a NSX Bridge Cluster using
# L2 gateway APIs.
# This field must be specified on one of the active neutron servers only.
# default_bridge_cluster_uuid =

View File

@ -10,7 +10,8 @@ setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0
usedevelop = True
install_command = {toxinidir}/tools/tox_install.sh {opts} {packages}
deps = -r{toxinidir}/requirements.txt
deps = -egit+https://git.openstack.org/openstack/networking-l2gw#egg=networking-l2gw
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
whitelist_externals = sh
commands =

View File

@ -1,2 +1,2 @@
28430956782d
279b70ac3ae8
393bf843b96

View File

@ -0,0 +1,43 @@
# Copyright 2015 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.
#
"""NSXv3 Add l2gwconnection table
Revision ID: 279b70ac3ae8
Revises: 28430956782d
Create Date: 2015-08-14 02:04:09.807926
"""
# revision identifiers, used by Alembic.
revision = '279b70ac3ae8'
down_revision = '28430956782d'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'nsx_l2gw_connection_mappings',
sa.Column('connection_id', sa.String(length=36), nullable=False),
sa.Column('port_id', sa.String(length=36), nullable=False),
sa.Column('bridge_endpoint_id', sa.String(length=36), nullable=False),
sa.ForeignKeyConstraint(['connection_id'],
['l2gatewayconnections.id'],
ondelete='CASCADE'),
sa.ForeignKeyConstraint(['port_id'], ['ports.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('connection_id'),
)

View File

@ -183,6 +183,10 @@ nsx_v3_opts = [
"starting Neutron with the NSX plugin.")),
cfg.StrOpt('default_edge_cluster_uuid',
help=_("Default edge cluster identifier")),
cfg.StrOpt('default_bridge_cluster_uuid',
help=_("Default bridge cluster identifier for L2 gateway. "
"This needs to be created in NSX before using the L2 "
"gateway service plugin.")),
cfg.IntOpt('retries',
default=10,
help=_('Maximum number of times to retry API request')),

View File

@ -137,3 +137,7 @@ class ResourceNotFound(ManagerError):
class StaleRevision(ManagerError):
pass
class NsxL2GWConnectionMappingNotFound(n_exc.NotFound):
message = _('Unable to find mapping for L2 gateway connection: %(conn)s')

View File

@ -41,3 +41,6 @@ ROUTER_TYPES = [ROUTER_TYPE_TIER0, ROUTER_TYPE_TIER1]
# L2 agent vif type
VIF_TYPE_DVS = 'dvs'
# NSXv3 L2 Gateway constants
BRIDGE_ENDPOINT = "BRIDGEENDPOINT"

View File

@ -21,6 +21,7 @@ from sqlalchemy.orm import exc
import neutron.db.api as db
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
from vmware_nsx.neutron.plugins.vmware.dbexts import nsx_models
LOG = logging.getLogger(__name__)
@ -203,3 +204,23 @@ def is_multiprovider_network(session, network_id):
return bool(
session.query(nsx_models.MultiProviderNetworks).filter_by(
network_id=network_id).first())
# NSXv3 L2 Gateway DB methods.
def add_l2gw_connection_mapping(session, connection_id, bridge_endpoint_id,
port_id):
with session.begin(subtransactions=True):
mapping = nsx_models.NsxL2GWConnectionMapping(
connection_id=connection_id,
port_id=port_id,
bridge_endpoint_id=bridge_endpoint_id)
session.add(mapping)
return mapping
def get_l2gw_connection_mapping(session, connection_id):
try:
return (session.query(nsx_models.NsxL2GWConnectionMapping).
filter_by(connection_id=connection_id).one())
except exc.NoResultFound:
raise nsx_exc.NsxL2GWConnectionMappingNotFound(conn=connection_id)

View File

@ -300,3 +300,17 @@ class NetworkQueueMapping(model_base.BASEV2):
models_v2.Network,
backref=orm.backref("qos_queue", uselist=False,
cascade='delete', lazy='joined'))
class NsxL2GWConnectionMapping(model_base.BASEV2):
"""Define a mapping between L2 gateway connection and bridge endpoint."""
__tablename__ = 'nsx_l2gw_connection_mappings'
connection_id = sa.Column(sa.String(36),
sa.ForeignKey("l2gatewayconnections.id",
ondelete="CASCADE"),
nullable=False,
primary_key=True)
port_id = sa.Column(sa.String(36),
sa.ForeignKey("ports.id", ondelete="CASCADE"),
nullable=False)
bridge_endpoint_id = sa.Column(sa.String(36), nullable=False)

View File

@ -282,3 +282,30 @@ def get_qos_switching_profile(profile_id):
def delete_qos_switching_profile(profile_id):
resource = 'switching-profiles/%s' % profile_id
client.delete_resource(resource)
def create_bridge_endpoint(device_name, seg_id, tags):
"""Create a bridge endpoint on the backend.
Create a bridge endpoint resource on a bridge cluster for the L2 gateway
network connection.
:param device_name: device_name actually refers to the bridge cluster's
UUID.
:param seg_id: integer representing the VLAN segmentation ID.
:param tags: nsx backend specific tags.
"""
resource = 'bridge-endpoints'
body = {'bridge_cluster_id': device_name,
'tags': tags,
'vlan': seg_id}
return client.create_resource(resource, body)
def delete_bridge_endpoint(bridge_endpoint_id):
"""Delete a bridge endpoint on the backend.
:param bridge_endpoint_id: string representing the UUID of the bridge
endpoint to be deleted.
"""
resource = 'bridge-endpoints/%s' % bridge_endpoint_id
client.delete_resource(resource)

View File

@ -27,13 +27,10 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from neutron.api.rpc.handlers import dhcp_rpc
from neutron.api.rpc.handlers import metadata_rpc
from neutron.api.v2 import attributes
from neutron.extensions import external_net as ext_net_extn
from neutron.extensions import extra_dhcp_opt as edo_ext
from neutron.extensions import l3
from neutron.extensions import portbindings as pbin
from neutron.extensions import providernet as pnet
from neutron.extensions import securitygroup as ext_sg
from neutron.callbacks import events
from neutron.callbacks import exceptions as callback_exc
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import constants as const
from neutron.common import exceptions as n_exc
from neutron.common import rpc as n_rpc
@ -49,12 +46,19 @@ from neutron.db import l3_gwmode_db
from neutron.db import models_v2
from neutron.db import portbindings_db
from neutron.db import securitygroups_db
from neutron.extensions import external_net as ext_net_extn
from neutron.extensions import extra_dhcp_opt as ext_edo
from neutron.extensions import l3
from neutron.extensions import portbindings as pbin
from neutron.extensions import providernet as pnet
from neutron.extensions import securitygroup as ext_sg
from neutron.i18n import _LE, _LI, _LW
from neutron.plugins.common import constants as plugin_const
from neutron.plugins.common import utils as n_utils
from vmware_nsx.neutron.plugins.vmware.common import config # noqa
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
from vmware_nsx.neutron.plugins.vmware.common import utils
from vmware_nsx.neutron.plugins.vmware.dbexts import db as nsx_db
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
@ -429,18 +433,28 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
# self.get_port(context, parent_name)
return parent_name, tag
def _create_port_at_the_backend(self, context, neutron_db, port_data):
def _create_port_at_the_backend(self, context, neutron_db,
port_data, l2gw_port_check):
tags = utils.build_v3_tags_payload(port_data)
parent_name, tag = self._get_data_from_binding_profile(
context, port_data)
address_bindings = self._build_address_bindings(port_data)
# FIXME(arosen): we might need to pull this out of the
# transaction here later.
vif_uuid = port_data['id']
attachment_type = nsx_constants.ATTACHMENT_VIF
# Change the attachment type for L2 gateway owned ports.
if l2gw_port_check:
# NSX backend requires the vif id be set to bridge endpoint id
# for ports plugged into a Bridge Endpoint.
vif_uuid = port_data.get('device_id')
attachment_type = port_data.get('device_owner')
result = nsxlib.create_logical_port(
lswitch_id=port_data['network_id'],
vif_uuid=port_data['id'], name=port_data['name'], tags=tags,
vif_uuid=vif_uuid, name=port_data['name'], tags=tags,
admin_state=port_data['admin_state_up'],
address_bindings=address_bindings,
attachment_type=attachment_type,
parent_name=parent_name, parent_tag=tag)
# TODO(salv-orlando): The logical switch identifier in the
@ -450,8 +464,8 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
neutron_db['network_id'], result['id'])
return result
def create_port(self, context, port):
dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, [])
def create_port(self, context, port, l2gw_port_check=False):
dhcp_opts = port['port'].get(ext_edo.EXTRADHCPOPTS, [])
port_id = uuidutils.generate_uuid()
port['port']['id'] = port_id
@ -468,7 +482,7 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
if not self._network_is_external(
context, port['port']['network_id']):
lport = self._create_port_at_the_backend(
context, neutron_db, port['port'])
context, neutron_db, port['port'], l2gw_port_check)
self._process_portbindings_create_and_update(context,
port['port'],
neutron_db)
@ -488,7 +502,27 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
context, lport['id'], [], sgids)
return neutron_db
def delete_port(self, context, port_id, l3_port_check=True):
def _pre_delete_port_check(self, context, port_id, l2gw_port_check):
"""Perform checks prior to deleting a port."""
try:
kwargs = {
'context': context,
'port_check': l2gw_port_check,
'port_id': port_id,
}
# Send delete port notification to any interested service plugin
registry.notify(
resources.PORT, events.BEFORE_DELETE, self, **kwargs)
except callback_exc.CallbackFailure as e:
if len(e.errors) == 1:
raise e.errors[0].error
raise n_exc.ServicePortInUse(port_id=port_id, reason=e)
def delete_port(self, context, port_id,
l3_port_check=True, l2gw_port_check=True):
# if needed, check to see if this is a port owned by
# a l2 gateway. If so, we should prevent deletion here
self._pre_delete_port_check(context, port_id, l2gw_port_check)
# if needed, check to see if this is a port owned by
# a l3 router. If so, we should prevent deletion here
if l3_port_check:

View File

@ -0,0 +1,266 @@
# Copyright 2015 VMware, 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 networking_l2gw.db.l2gateway import l2gateway_db
from networking_l2gw.services.l2gateway.common import constants as l2gw_const
from networking_l2gw.services.l2gateway import exceptions as l2gw_exc
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import uuidutils
from neutron.api.v2 import attributes
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import exceptions as n_exc
from neutron import context
from neutron.extensions import providernet
from neutron.i18n import _LE, _LI
from neutron import manager
from neutron.plugins.common import utils as n_utils
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
from vmware_nsx.neutron.plugins.vmware.common import utils as nsx_utils
from vmware_nsx.neutron.plugins.vmware.dbexts import db as nsx_db
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
LOG = logging.getLogger(__name__)
class NsxV3Driver(l2gateway_db.L2GatewayMixin):
"""Class to handle API calls for L2 gateway and NSXv3 backend."""
gateway_resource = l2gw_const.GATEWAY_RESOURCE_NAME
def __init__(self):
# Create a default L2 gateway if default_bridge_cluster_uuid is
# provided in nsx.ini
self._ensure_default_l2_gateway()
self.subscribe_callback_notifications()
LOG.debug("Initialization complete for NSXv3 driver for "
"L2 gateway service plugin.")
@property
def _core_plugin(self):
return manager.NeutronManager.get_plugin()
def subscribe_callback_notifications(self):
registry.subscribe(self._prevent_l2gw_port_delete, resources.PORT,
events.BEFORE_DELETE)
def _ensure_default_l2_gateway(self):
"""
Create a default logical L2 gateway.
Create a logical L2 gateway in the neutron database if the
default_bridge_cluster_uuid config parameter is set and if it is
not previously created. If not set, return.
"""
def_l2gw_uuid = cfg.CONF.nsx_v3.default_bridge_cluster_uuid
# Return if no default_bridge_cluster_uuid set in config
if not def_l2gw_uuid:
LOG.info(_LI("NSX: Default bridge cluster UUID not configured "
"in nsx.ini. No default L2 gateway created."))
return
admin_ctx = context.get_admin_context()
# Optimistically create the default L2 gateway in neutron DB
device = {'device_name': def_l2gw_uuid,
'interfaces': [{'name': 'default-bridge-cluster'}]}
def_l2gw = {'name': 'default-l2gw',
'devices': [device]}
l2gw_dict = {self.gateway_resource: def_l2gw}
l2_gateway = self.create_l2_gateway(admin_ctx, l2gw_dict)
# Verify that only one default L2 gateway is created
def_l2gw_exists = False
l2gateways = self._get_l2_gateways(admin_ctx)
for l2gateway in l2gateways:
# Since we ensure L2 gateway is created with only 1 device, we use
# the first device in the list.
if l2gateway['devices'][0]['device_name'] == def_l2gw_uuid:
if def_l2gw_exists:
LOG.info(_LI("Default L2 gateway is already created."))
try:
# Try deleting this duplicate default L2 gateway
self.delete_l2_gateway(admin_ctx, l2gateway['id'])
except l2gw_exc.L2GatewayInUse:
# If the L2 gateway we are trying to delete is in
# use then we should delete the L2 gateway which
# we just created ensuring there is only one
# default L2 gateway in the database.
self.delete_l2_gateway(admin_ctx, l2_gateway['id'])
else:
def_l2gw_exists = True
return l2_gateway
def _prevent_l2gw_port_delete(self, resource, event, trigger, **kwargs):
context = kwargs.get('context')
port_id = kwargs.get('port_id')
port_check = kwargs.get('port_check')
if port_check:
self.prevent_l2gw_port_deletion(context, port_id)
def _validate_device_list(self, devices):
# In NSXv3, one L2 gateway is mapped to one bridge cluster.
# So we expect only one device to be configured as part of
# a L2 gateway resource. The name of the device must be the bridge
# cluster's UUID.
if len(devices) != 1:
msg = _("Only a single device is supported for one L2 gateway")
raise n_exc.InvalidInput(error_message=msg)
if not uuidutils.is_uuid_like(devices[0]['device_name']):
msg = _("Device name must be configured with a UUID")
raise n_exc.InvalidInput(error_message=msg)
def create_l2_gateway(self, context, l2_gateway):
"""Create a logical L2 gateway."""
gw = l2_gateway[self.gateway_resource]
devices = gw['devices']
self._validate_device_list(devices)
return super(NsxV3Driver, self).create_l2_gateway(context,
l2_gateway)
def _validate_network(self, context, network_id):
network = self._core_plugin.get_network(context, network_id)
network_type = network.get(providernet.NETWORK_TYPE)
# If network is a provider network, verify whether it is of type VXLAN
if network_type and network_type != nsx_utils.NsxV3NetworkTypes.VXLAN:
msg = (_("Unsupported network type %s for L2 gateway "
"connection. Only VXLAN network type supported") %
network_type)
raise n_exc.InvalidInput(error_message=msg)
def _validate_segment_id(self, seg_id):
if not seg_id:
raise l2gw_exc.L2GatewaySegmentationRequired
return n_utils.is_valid_vlan_tag(seg_id)
def create_l2_gateway_connection(self, context, l2_gateway_connection):
"""Create a L2 gateway connection."""
#TODO(abhiraut): Move backend logic in a separate method
gw_connection = l2_gateway_connection.get(l2gw_const.
CONNECTION_RESOURCE_NAME)
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
self._validate_network(context, network_id)
l2gw_connection = super(
NsxV3Driver, self).create_l2_gateway_connection(
context, l2_gateway_connection)
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
devices = self._get_l2_gateway_devices(context, l2gw_id)
# In NSXv3, there will be only one device configured per L2 gateway.
# The name of the device shall carry the backend bridge cluster's UUID.
device_name = devices[0].get('device_name')
# The seg-id will be provided either during gateway create or gateway
# connection create. l2gateway_db_mixin makes sure that it is
# configured one way or the other.
seg_id = gw_connection.get(l2gw_const.SEG_ID)
if seg_id is None:
seg_id = devices[0]['interfaces'][0].get('segmentation_id')
self._validate_segment_id(seg_id)
try:
tags = nsx_utils.build_v3_tags_payload(gw_connection)
bridge_endpoint = nsxlib.create_bridge_endpoint(
device_name=device_name,
seg_id=seg_id,
tags=tags)
except nsx_exc.ManagerError:
LOG.exception(_LE("Unable to update NSX backend, rolling back "
"changes on neutron"))
with excutils.save_and_reraise_exception():
super(NsxV3Driver,
self).delete_l2_gateway_connection(context,
l2gw_connection['id'])
# Create a logical port and connect it to the bridge endpoint.
tenant_id = self._core_plugin._get_tenant_id_for_create(context,
gw_connection)
# _get_tenant_id_for_create might return None in some cases.
# This is not acceptable for the NSX plugin
if context.is_admin and not tenant_id:
tenant_id = context.tenant_id
#TODO(abhiraut): Consider specifying the name of the port
port_dict = {'port': {
'tenant_id': tenant_id,
'network_id': network_id,
'mac_address': attributes.ATTR_NOT_SPECIFIED,
'admin_state_up': True,
'fixed_ips': [],
'device_id': bridge_endpoint['id'],
'device_owner': nsx_constants.BRIDGE_ENDPOINT,
'name': '', }}
try:
port = self._core_plugin.create_port(context, port_dict)
# Deallocate IP address from the port.
for fixed_ip in port.get('fixed_ips', []):
self._core_plugin._delete_ip_allocation(context, network_id,
fixed_ip['subnet_id'],
fixed_ip['ip_address'])
LOG.debug("IP addresses deallocated on port %s", port['id'])
except (nsx_exc.ManagerError,
n_exc.NeutronException):
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Unable to create L2 gateway port, "
"rolling back changes on neutron"))
nsxlib.delete_bridge_endpoint(bridge_endpoint['id'])
super(NsxV3Driver,
self).delete_l2_gateway_connection(context,
l2gw_connection['id'])
try:
# Update neutron's database with the mappings.
nsx_db.add_l2gw_connection_mapping(
session=context.session,
connection_id=l2gw_connection['id'],
bridge_endpoint_id=bridge_endpoint['id'],
port_id=port['id'])
except db_exc.DBError:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Unable to add L2 gateway connection "
"mappings, rolling back changes on neutron"))
nsxlib.delete_bridge_endpoint(bridge_endpoint['id'])
super(NsxV3Driver,
self).delete_l2_gateway_connection(context,
l2gw_connection['id'])
return l2gw_connection
def delete_l2_gateway_connection(self, context, l2_gateway_connection):
"""Delete a L2 gateway connection."""
conn_mapping = nsx_db.get_l2gw_connection_mapping(
session=context.session,
connection_id=l2_gateway_connection)
bridge_endpoint_id = conn_mapping.get('bridge_endpoint_id')
# Delete the logical port from the bridge endpoint.
self._core_plugin.delete_port(context=context,
port_id=conn_mapping.get('port_id'),
l2gw_port_check=False)
try:
nsxlib.delete_bridge_endpoint(bridge_endpoint_id)
except nsx_exc.ManagerError:
LOG.exception(_LE("Unable to delete bridge endpoint %s on the "
"backend.") % bridge_endpoint_id)
return (super(NsxV3Driver, self).
delete_l2_gateway_connection(context,
l2_gateway_connection))
def prevent_l2gw_port_deletion(self, context, port_id):
"""Prevent core plugin from deleting L2 gateway port."""
try:
port = self._core_plugin.get_port(context, port_id)
except n_exc.PortNotFound:
return
if port['device_owner'] == nsx_constants.BRIDGE_ENDPOINT:
reason = _("has device owner %s") % port['device_owner']
raise n_exc.ServicePortInUse(port_id=port_id, reason=reason)

View File

@ -16,6 +16,8 @@
import os
from networking_l2gw.db.l2gateway import l2gateway_models # noqa
from vmware_nsx.neutron.plugins.vmware.api_client import client as nsx_client
from vmware_nsx.neutron.plugins.vmware.api_client import eventlet_client
from vmware_nsx.neutron.plugins.vmware import extensions

View File

@ -0,0 +1,74 @@
# Copyright (c) 2015 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
from neutron import context
from neutron.tests import base
from networking_l2gw.tests.unit.db import test_l2gw_db
from vmware_nsx.neutron.services.l2gateway import nsx_v3_driver
from vmware_nsx.neutron.services.l2gateway import plugin as l2gw_plugin
from oslo_config import cfg
from oslo_utils import uuidutils
NSX_V3_DRIVER_CLASS_PATH = ('vmware_nsx.neutron.services.l2gateway.'
'nsx_v3_driver.NsxV3Driver')
class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
base.BaseTestCase):
def setUp(self):
super(TestNsxV3L2GatewayDriver, self).setUp()
cfg.CONF.set_override("nsx_l2gw_driver",
NSX_V3_DRIVER_CLASS_PATH, 'NSX')
self.l2gw_plugin = l2gw_plugin.NsxL2GatewayPlugin()
self.driver = nsx_v3_driver.NsxV3Driver()
self.context = context.get_admin_context()
def test_nsxl2gw_driver_init(self):
with mock.patch.object(nsx_v3_driver.NsxV3Driver,
'_ensure_default_l2_gateway') as def_gw:
with mock.patch.object(nsx_v3_driver.NsxV3Driver,
'subscribe_callback_notifications') as sub:
with mock.patch.object(nsx_v3_driver.LOG,
'debug') as debug:
l2gw_plugin.NsxL2GatewayPlugin()
self.assertTrue(def_gw.called)
self.assertTrue(sub.called)
self.assertTrue(debug.called)
def test_create_default_l2_gateway(self):
def_bridge_cluster_id = uuidutils.generate_uuid()
with mock.patch.object(nsx_v3_driver.NsxV3Driver,
'subscribe_callback_notifications'):
cfg.CONF.set_override("default_bridge_cluster_uuid",
def_bridge_cluster_id,
"nsx_v3")
l2gw_plugin.NsxL2GatewayPlugin()
l2gws = self.driver._get_l2_gateways(self.context)
def_l2gw = None
for l2gw in l2gws:
for device in l2gw['devices']:
if device['device_name'] == def_bridge_cluster_id:
def_l2gw = l2gw
self.assertIsNotNone(def_l2gw)
self.assertTrue(def_l2gw.devices[0].device_name,
def_bridge_cluster_id)
self.assertTrue(def_l2gw.devices[0].interfaces[0].interface_name,
'default-bridge-cluster')