NSX|v3 replace configuration uuids with names

Support configuration of name or uuid (instead of only uuid) for 4 nsx_v3
parameters: default_overlay_tz, default_vlan_tz, default_bridge_cluster
and default_tier0_router.

Assert on init if the uuid or name was no found on the backend, or if the
name is not unique.

DocImpact: Configuration options default_overlay_tz_uuid, default_vlan_tz_uuid,
           default_bridge_cluster_uuid and default_tier0_router_uuid were
           replaced with default_overlay_tz, default_vlan_tz, default_bridge_cluster
           and default_tier0_router and support name or uuid now.

Change-Id: Id153d4d69165b161c04c403b578657c51af20e9c
This commit is contained in:
Adit Sarfaty 2016-04-18 15:12:19 +03:00
parent ae3023dc1e
commit a88b99b6c9
10 changed files with 167 additions and 46 deletions

View File

@ -100,10 +100,10 @@ function _nsxv3_ini_set {
} }
function neutron_plugin_configure_service { function neutron_plugin_configure_service {
_nsxv3_ini_set default_overlay_tz_uuid $DEFAULT_OVERLAY_TZ_UUID "The VMware NSX plugin won't work without a default transport zone." _nsxv3_ini_set default_overlay_tz $DEFAULT_OVERLAY_TZ_UUID "The VMware NSX plugin won't work without a default transport zone."
_nsxv3_ini_set default_vlan_tz_uuid $DEFAULT_VLAN_TZ_UUID _nsxv3_ini_set default_vlan_tz $DEFAULT_VLAN_TZ_UUID
if [[ "$DEFAULT_TIER0_ROUTER_UUID" != "" ]]; then if [[ "$DEFAULT_TIER0_ROUTER_UUID" != "" ]]; then
_nsxv3_ini_set default_tier0_router_uuid $DEFAULT_TIER0_ROUTER_UUID _nsxv3_ini_set default_tier0_router $DEFAULT_TIER0_ROUTER_UUID
Q_L3_ENABLED=True Q_L3_ENABLED=True
Q_L3_ROUTER_PER_TENANT=True Q_L3_ROUTER_PER_TENANT=True
fi fi
@ -123,7 +123,7 @@ function neutron_plugin_configure_service {
_nsxv3_ini_set retries $NSX_RETRIES _nsxv3_ini_set retries $NSX_RETRIES
_nsxv3_ini_set insecure $NSX_INSECURE _nsxv3_ini_set insecure $NSX_INSECURE
_nsxv3_ini_set ca_file $NSX_CA_FILE _nsxv3_ini_set ca_file $NSX_CA_FILE
_nsxv3_ini_set default_bridge_cluster_uuid $DEFAULT_BRIDGE_CLUSTER_UUID _nsxv3_ini_set default_bridge_cluster $DEFAULT_BRIDGE_CLUSTER_UUID
} }
function neutron_plugin_setup_interface_driver { function neutron_plugin_setup_interface_driver {

View File

@ -0,0 +1,13 @@
---
prelude: >
The 'default_tier0_router_uuid', 'default_overlay_tz_uuid',
'default_vlan_tz_uuid', and 'default_bridge_cluster_uuid'
options have been deprecated and replaced by 'default_tier0_router',
'default_overlay_tz', 'default_vlan_tz', and 'default_bridge_cluster'
respectively, which can accept both name or uuid
deprecations:
- The 'default_tier0_router_uuid', 'default_overlay_tz_uuid',
'default_vlan_tz_uuid', and 'default_bridge_cluster_uuid'
options have been deprecated and replaced by 'default_tier0_router',
'default_overlay_tz', 'default_vlan_tz', and 'default_bridge_cluster'
respectively, which can accept both name or uuid

View File

@ -249,25 +249,30 @@ nsx_v3_opts = [
"[<scheme>://]<ip_adress>[:<port>]\nIf scheme is not " "[<scheme>://]<ip_adress>[:<port>]\nIf scheme is not "
"provided https is used. If port is not provided port " "provided https is used. If port is not provided port "
"80 is used for http and port 443 for https.")), "80 is used for http and port 443 for https.")),
cfg.StrOpt('default_overlay_tz_uuid', cfg.StrOpt('default_overlay_tz',
deprecated_name='default_tz_uuid', deprecated_name='default_overlay_tz_uuid',
help=_("This is the UUID of the default NSX overlay transport " help=_("This is the name or UUID of the default NSX overlay "
"zone that will be used for creating tunneled isolated " "transport zone that will be used for creating "
"Neutron networks. It needs to be created in NSX " "tunneled isolated Neutron networks. It needs to be "
"before starting Neutron with the NSX plugin.")), "created in NSX before starting Neutron with the NSX "
cfg.StrOpt('default_vlan_tz_uuid', "plugin.")),
cfg.StrOpt('default_vlan_tz',
deprecated_name='default_vlan_tz_uuid',
help=_("(Optional) Only required when creating VLAN or flat " help=_("(Optional) Only required when creating VLAN or flat "
"provider networks. UUID of default NSX VLAN transport " "provider networks. Name or UUID of default NSX VLAN "
"zone that will be used for bridging between Neutron " "transport zone that will be used for bridging between "
"networks, if no physical network has been specified")), "Neutron networks, if no physical network has been "
cfg.StrOpt('default_bridge_cluster_uuid', "specified")),
help=_("(Optional) UUID of the default NSX bridge cluster that " cfg.StrOpt('default_bridge_cluster',
"will be used to perform L2 gateway bridging between " deprecated_name='default_bridge_cluster_uuid',
"VXLAN and VLAN networks. If default bridge cluster " help=_("(Optional) Name or UUID of the default NSX bridge "
"UUID is not specified, admin will have to manually " "cluster that will be used to perform L2 gateway "
"create a L2 gateway corresponding to a NSX Bridge " "bridging between VXLAN and VLAN networks. If default "
"Cluster using L2 gateway APIs. This field must be " "bridge cluster UUID is not specified, admin will have "
"specified on one of the active neutron servers only.")), "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.")),
cfg.IntOpt('retries', cfg.IntOpt('retries',
default=10, default=10,
help=_('Maximum number of times to retry API requests upon ' help=_('Maximum number of times to retry API requests upon '
@ -306,10 +311,11 @@ nsx_v3_opts = [
cfg.IntOpt('redirects', cfg.IntOpt('redirects',
default=2, default=2,
help=_('Number of times a HTTP redirect should be followed.')), help=_('Number of times a HTTP redirect should be followed.')),
cfg.StrOpt('default_tier0_router_uuid', cfg.StrOpt('default_tier0_router',
help=_("UUID of the default tier0 router that will be used for " deprecated_name='default_tier0_router_uuid',
"connecting to tier1 logical routers and configuring " help=_("Name or UUID of the default tier0 router that will be "
"external networks")), "used for connecting to tier1 logical routers and "
"configuring external networks")),
cfg.IntOpt('number_of_nested_groups', cfg.IntOpt('number_of_nested_groups',
default=8, default=8,
help=_("(Optional) The number of nested groups which are used " help=_("(Optional) The number of nested groups which are used "

View File

@ -231,3 +231,57 @@ def delete_bridge_endpoint(bridge_endpoint_id):
""" """
resource = 'bridge-endpoints/%s' % bridge_endpoint_id resource = 'bridge-endpoints/%s' % bridge_endpoint_id
client.delete_resource(resource) client.delete_resource(resource)
def _get_resource_by_name_or_id(name_or_id, resource):
all_results = client.get_resource(resource)['results']
matched_results = []
for rs in all_results:
if rs.get('id') == name_or_id:
# Matched by id - must be unique
return name_or_id
if rs.get('display_name') == name_or_id:
# Matched by name - add to the list to verify it is unique
matched_results.append(rs)
if len(matched_results) == 0:
err_msg = (_("Could not find %(resource)s %(name)s") %
{'name': name_or_id, 'resource': resource})
raise nsx_exc.NsxPluginException(err_msg=err_msg)
elif len(matched_results) > 1:
err_msg = (_("Found multiple %(resource)s named %(name)s") %
{'name': name_or_id, 'resource': resource})
raise nsx_exc.NsxPluginException(err_msg=err_msg)
return matched_results[0].get('id')
def get_transport_zone_id_by_name_or_id(name_or_id):
"""Get a transport zone by it's display name or uuid
Return the transport zone data, or raise an exception if not found or
not unique
"""
return _get_resource_by_name_or_id(name_or_id, 'transport-zones')
def get_logical_router_id_by_name_or_id(name_or_id):
"""Get a logical router by it's display name or uuid
Return the logical router data, or raise an exception if not found or
not unique
"""
return _get_resource_by_name_or_id(name_or_id, 'logical-routers')
def get_bridge_cluster_id_by_name_or_id(name_or_id):
"""Get a bridge cluster by it's display name or uuid
Return the bridge cluster data, or raise an exception if not found or
not unique
"""
return _get_resource_by_name_or_id(name_or_id, 'bridge-clusters')

View File

@ -180,6 +180,31 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
raise nsx_exc.NsxPluginException(msg) raise nsx_exc.NsxPluginException(msg)
self._unsubscribe_callback_events() self._unsubscribe_callback_events()
# translate configured transport zones/rotuers names to uuid
self._translate_configured_names_2_uuids()
def _translate_configured_names_2_uuids(self):
# default VLAN transport zone name / uuid
self._default_vlan_tz_uuid = None
if cfg.CONF.nsx_v3.default_vlan_tz:
tz_id = nsxlib.get_transport_zone_id_by_name_or_id(
cfg.CONF.nsx_v3.default_vlan_tz)
self._default_vlan_tz_uuid = tz_id
# default overlay transport zone name / uuid
self._default_overlay_tz_uuid = None
if cfg.CONF.nsx_v3.default_overlay_tz:
tz_id = nsxlib.get_transport_zone_id_by_name_or_id(
cfg.CONF.nsx_v3.default_overlay_tz)
self._default_overlay_tz_uuid = tz_id
# default tier0 router
self._default_tier0_router = None
if cfg.CONF.nsx_v3.default_tier0_router:
rtr_id = nsxlib.get_logical_router_id_by_name_or_id(
cfg.CONF.nsx_v3.default_tier0_router)
self._default_tier0_router = rtr_id
def _extend_port_dict_binding(self, context, port_data): def _extend_port_dict_binding(self, context, port_data):
port_data[pbin.VIF_TYPE] = pbin.VIF_TYPE_OVS port_data[pbin.VIF_TYPE] = pbin.VIF_TYPE_OVS
port_data[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL port_data[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL
@ -344,11 +369,11 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
# Set VLAN id to 0 for flat networks # Set VLAN id to 0 for flat networks
vlan_id = '0' vlan_id = '0'
if physical_net is None: if physical_net is None:
physical_net = cfg.CONF.nsx_v3.default_vlan_tz_uuid physical_net = self._default_vlan_tz_uuid
elif net_type == utils.NsxV3NetworkTypes.VLAN: elif net_type == utils.NsxV3NetworkTypes.VLAN:
# Use default VLAN transport zone if physical network not given # Use default VLAN transport zone if physical network not given
if physical_net is None: if physical_net is None:
physical_net = cfg.CONF.nsx_v3.default_vlan_tz_uuid physical_net = self._default_vlan_tz_uuid
# Validate VLAN id # Validate VLAN id
if not vlan_id: if not vlan_id:
@ -394,7 +419,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
if physical_net is None: if physical_net is None:
# Default to transport type overlay # Default to transport type overlay
physical_net = cfg.CONF.nsx_v3.default_overlay_tz_uuid physical_net = self._default_overlay_tz_uuid
return is_provider_net, net_type, physical_net, vlan_id return is_provider_net, net_type, physical_net, vlan_id
@ -407,7 +432,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
def _validate_external_net_create(self, net_data): def _validate_external_net_create(self, net_data):
is_provider_net = False is_provider_net = False
if not attributes.is_attr_set(net_data.get(pnet.PHYSICAL_NETWORK)): if not attributes.is_attr_set(net_data.get(pnet.PHYSICAL_NETWORK)):
tier0_uuid = cfg.CONF.nsx_v3.default_tier0_router_uuid tier0_uuid = self._default_tier0_router
else: else:
tier0_uuid = net_data[pnet.PHYSICAL_NETWORK] tier0_uuid = net_data[pnet.PHYSICAL_NETWORK]
is_provider_net = True is_provider_net = True
@ -1237,7 +1262,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
return return
network = self.get_network(context, network_id) network = self.get_network(context, network_id)
if not network.get(pnet.PHYSICAL_NETWORK): if not network.get(pnet.PHYSICAL_NETWORK):
return cfg.CONF.nsx_v3.default_tier0_router_uuid return self._default_tier0_router
else: else:
return network.get(pnet.PHYSICAL_NETWORK) return network.get(pnet.PHYSICAL_NETWORK)

View File

@ -49,7 +49,7 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
gateway_resource = l2gw_const.GATEWAY_RESOURCE_NAME gateway_resource = l2gw_const.GATEWAY_RESOURCE_NAME
def __init__(self): def __init__(self):
# Create a default L2 gateway if default_bridge_cluster_uuid is # Create a default L2 gateway if default_bridge_cluster is
# provided in nsx.ini # provided in nsx.ini
self._ensure_default_l2_gateway() self._ensure_default_l2_gateway()
self.subscribe_callback_notifications() self.subscribe_callback_notifications()
@ -69,16 +69,20 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
Create a default logical L2 gateway. Create a default logical L2 gateway.
Create a logical L2 gateway in the neutron database if the Create a logical L2 gateway in the neutron database if the
default_bridge_cluster_uuid config parameter is set and if it is default_bridge_cluster config parameter is set and if it is
not previously created. If not set, return. not previously created. If not set, return.
""" """
def_l2gw_uuid = cfg.CONF.nsx_v3.default_bridge_cluster_uuid def_l2gw_name = cfg.CONF.nsx_v3.default_bridge_cluster
# Return if no default_bridge_cluster_uuid set in config # Return if no default_bridge_cluster set in config
if not def_l2gw_uuid: if not def_l2gw_name:
LOG.info(_LI("NSX: Default bridge cluster UUID not configured " LOG.info(_LI("NSX: Default bridge cluster not configured "
"in nsx.ini. No default L2 gateway created.")) "in nsx.ini. No default L2 gateway created."))
return return
admin_ctx = context.get_admin_context() admin_ctx = context.get_admin_context()
def_l2gw_uuid = nsxlib.get_bridge_cluster_id_by_name_or_id(
def_l2gw_name)
# Optimistically create the default L2 gateway in neutron DB # Optimistically create the default L2 gateway in neutron DB
device = {'device_name': def_l2gw_uuid, device = {'device_name': def_l2gw_uuid,
'interfaces': [{'name': 'default-bridge-cluster'}]} 'interfaces': [{'name': 'default-bridge-cluster'}]}

View File

@ -22,6 +22,7 @@ from vmware_nsx.common import nsx_constants
FAKE_NAME = "fake_name" FAKE_NAME = "fake_name"
DEFAULT_TIER0_ROUTER_UUID = "efad0078-9204-4b46-a2d8-d4dd31ed448f" DEFAULT_TIER0_ROUTER_UUID = "efad0078-9204-4b46-a2d8-d4dd31ed448f"
NSX_BRIDGE_CLUSTER_NAME = 'default bridge cluster'
FAKE_MANAGER = "fake_manager_ip" FAKE_MANAGER = "fake_manager_ip"

View File

@ -123,6 +123,20 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase,
'display_name': nsx_plugin.NSX_V3_NO_PSEC_PROFILE_NAME 'display_name': nsx_plugin.NSX_V3_NO_PSEC_PROFILE_NAME
}), headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS) }), headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS)
self.mock_api.post(
'api/v1/transport-zones',
data=jsonutils.dumps({
'id': uuidutils.generate_uuid(),
'display_name': nsxlib_testcase.NSX_TZ_NAME
}), headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS)
self.mock_api.post(
'api/v1/bridge-clusters',
data=jsonutils.dumps({
'id': uuidutils.generate_uuid(),
'display_name': nsx_v3_mocks.NSX_BRIDGE_CLUSTER_NAME
}), headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS)
super(NsxV3PluginTestCaseMixin, self).setUp(plugin=plugin, super(NsxV3PluginTestCaseMixin, self).setUp(plugin=plugin,
ext_mgr=ext_mgr) ext_mgr=ext_mgr)

View File

@ -18,8 +18,8 @@ import mock
import unittest import unittest
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import uuidutils
from requests import exceptions as requests_exceptions from requests import exceptions as requests_exceptions
from vmware_nsx.nsxlib.v3 import client as nsx_client from vmware_nsx.nsxlib.v3 import client as nsx_client
from vmware_nsx.nsxlib.v3 import cluster as nsx_cluster from vmware_nsx.nsxlib.v3 import cluster as nsx_cluster
@ -30,6 +30,7 @@ NSX_INSECURE = False
NSX_CERT = '/opt/stack/certs/nsx.pem' NSX_CERT = '/opt/stack/certs/nsx.pem'
NSX_HTTP_TIMEOUT = 10 NSX_HTTP_TIMEOUT = 10
NSX_HTTP_READ_TIMEOUT = 180 NSX_HTTP_READ_TIMEOUT = 180
NSX_TZ_NAME = 'default transport zone'
V3_CLIENT_PKG = 'vmware_nsx.nsxlib.v3.client' V3_CLIENT_PKG = 'vmware_nsx.nsxlib.v3.client'
BRIDGE_FNS = ['create_resource', 'delete_resource', BRIDGE_FNS = ['create_resource', 'delete_resource',
@ -40,8 +41,7 @@ class NsxLibTestCase(unittest.TestCase):
@classmethod @classmethod
def setup_conf_overrides(cls): def setup_conf_overrides(cls):
cfg.CONF.set_override('default_overlay_tz_uuid', cfg.CONF.set_override('default_overlay_tz', NSX_TZ_NAME, 'nsx_v3')
uuidutils.generate_uuid(), 'nsx_v3')
cfg.CONF.set_override('nsx_api_user', NSX_USER, 'nsx_v3') cfg.CONF.set_override('nsx_api_user', NSX_USER, 'nsx_v3')
cfg.CONF.set_override('nsx_api_password', NSX_PASSWORD, 'nsx_v3') cfg.CONF.set_override('nsx_api_password', NSX_PASSWORD, 'nsx_v3')
cfg.CONF.set_override('nsx_api_managers', [NSX_MANAGER], 'nsx_v3') cfg.CONF.set_override('nsx_api_managers', [NSX_MANAGER], 'nsx_v3')

View File

@ -26,8 +26,10 @@ from neutron.tests import base
from neutron_lib import exceptions as n_exc from neutron_lib import exceptions as n_exc
from vmware_nsx.common import nsx_constants from vmware_nsx.common import nsx_constants
from vmware_nsx.nsxlib import v3 as nsxlib
from vmware_nsx.services.l2gateway.common import plugin as l2gw_plugin from vmware_nsx.services.l2gateway.common import plugin as l2gw_plugin
from vmware_nsx.services.l2gateway.nsx_v3 import driver as nsx_v3_driver from vmware_nsx.services.l2gateway.nsx_v3 import driver as nsx_v3_driver
from vmware_nsx.tests.unit.nsx_v3 import mocks as nsx_v3_mocks
from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_nsx_v3_plugin from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_nsx_v3_plugin
@ -69,14 +71,16 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
self.assertTrue(debug.called) self.assertTrue(debug.called)
def test_create_default_l2_gateway(self): def test_create_default_l2_gateway(self):
def_bridge_cluster_id = uuidutils.generate_uuid() def_bridge_cluster_name = nsx_v3_mocks.NSX_BRIDGE_CLUSTER_NAME
with mock.patch.object(nsx_v3_driver.NsxV3Driver, with mock.patch.object(nsx_v3_driver.NsxV3Driver,
'subscribe_callback_notifications'): 'subscribe_callback_notifications'):
cfg.CONF.set_override("default_bridge_cluster_uuid", cfg.CONF.set_override("default_bridge_cluster",
def_bridge_cluster_id, def_bridge_cluster_name,
"nsx_v3") "nsx_v3")
l2gw_plugin.NsxL2GatewayPlugin() l2gw_plugin.NsxL2GatewayPlugin()
l2gws = self.driver._get_l2_gateways(self.context) l2gws = self.driver._get_l2_gateways(self.context)
def_bridge_cluster_id = nsxlib.get_bridge_cluster_id_by_name_or_id(
def_bridge_cluster_name)
def_l2gw = None def_l2gw = None
for l2gw in l2gws: for l2gw in l2gws:
for device in l2gw['devices']: for device in l2gw['devices']:
@ -89,11 +93,11 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
'default-bridge-cluster') 'default-bridge-cluster')
def test_create_duplicate_default_l2_gateway_noop(self): def test_create_duplicate_default_l2_gateway_noop(self):
def_bridge_cluster_id = uuidutils.generate_uuid() def_bridge_cluster_name = nsx_v3_mocks.NSX_BRIDGE_CLUSTER_NAME
with mock.patch.object(nsx_v3_driver.NsxV3Driver, with mock.patch.object(nsx_v3_driver.NsxV3Driver,
'subscribe_callback_notifications'): 'subscribe_callback_notifications'):
cfg.CONF.set_override("default_bridge_cluster_uuid", cfg.CONF.set_override("default_bridge_cluster",
def_bridge_cluster_id, def_bridge_cluster_name,
"nsx_v3") "nsx_v3")
l2gw_plugin.NsxL2GatewayPlugin() l2gw_plugin.NsxL2GatewayPlugin()
l2gw_plugin.NsxL2GatewayPlugin() l2gw_plugin.NsxL2GatewayPlugin()