From b0a02917ee0065d4a6a335bc9790f668a0e1d2a4 Mon Sep 17 00:00:00 2001
From: Adit Sarfaty <asarfaty@vmware.com>
Date: Mon, 8 Jan 2018 10:14:46 +0200
Subject: [PATCH] TVD availability zones

1. Do not allow the same availability zone to be configured for both
   NSX-V and NSX-T
2. Adding separate configurations for the nsx-v/t default availability
zones under the tvd configuration section:
[nsx_tvd]
nsx_v_default_availability_zones = zone2
nsx_v3_default_availability_zones = zone1

Change-Id: Ic77dae9398b8281b8ea4d2988447907d1ac55c90
---
 devstack/lib/vmware_nsx_tvd                   |  3 ---
 vmware_nsx/common/availability_zones.py       | 26 +++++++------------
 vmware_nsx/common/config.py                   | 10 +++++++
 vmware_nsx/plugins/nsx/plugin.py              | 12 +++++++++
 .../plugins/nsx_v/availability_zones.py       |  8 ++++--
 vmware_nsx/plugins/nsx_v/plugin.py            |  3 +--
 .../plugins/nsx_v3/availability_zones.py      |  8 ++++--
 vmware_nsx/plugins/nsx_v3/plugin.py           |  7 ++---
 vmware_nsx/tests/unit/nsx_tvd/test_plugin.py  |  8 ++++++
 9 files changed, 55 insertions(+), 30 deletions(-)

diff --git a/devstack/lib/vmware_nsx_tvd b/devstack/lib/vmware_nsx_tvd
index e1c060fd2d..be22088795 100644
--- a/devstack/lib/vmware_nsx_tvd
+++ b/devstack/lib/vmware_nsx_tvd
@@ -36,9 +36,6 @@ NATIVE_DHCP_METADATA=${NATIVE_DHCP_METADATA:-True}
 NATIVE_METADATA_ROUTE=${NATIVE_METADATA_ROUTE:-169.254.169.254/31}
 METADATA_PROXY_SHARED_SECRET=${METADATA_PROXY_SHARED_SECRET:-}
 
-# Default AZ
-NSX_DEFAULT_AZ=${NSX_DEFAULT_AZ:-defaultv3}
-
 # Save trace setting
 NSX_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
diff --git a/vmware_nsx/common/availability_zones.py b/vmware_nsx/common/availability_zones.py
index e5c330dba7..2be7771828 100644
--- a/vmware_nsx/common/availability_zones.py
+++ b/vmware_nsx/common/availability_zones.py
@@ -15,8 +15,6 @@
 
 import abc
 
-from oslo_config import cfg
-
 from neutron_lib.api.definitions import availability_zone as az_def
 from neutron_lib import exceptions as n_exc
 from neutron_lib.exceptions import availability_zone as az_exc
@@ -78,7 +76,7 @@ class ConfiguredAvailabilityZones(object):
 
     default_name = DEFAULT_NAME
 
-    def __init__(self, az_conf, az_class, validate_default=True):
+    def __init__(self, az_conf, az_class, default_availability_zones=None):
         self.availability_zones = {}
 
         # Add the configured availability zones
@@ -91,24 +89,20 @@ class ConfiguredAvailabilityZones(object):
         self.availability_zones[obj.name] = obj
 
         # validate the default az:
-        if cfg.CONF.default_availability_zones:
+        if default_availability_zones:
             # we support only 1 default az
-            if len(cfg.CONF.default_availability_zones) > 1:
+            if len(default_availability_zones) > 1:
                 raise nsx_exc.NsxInvalidConfiguration(
                     opt_name="default_availability_zones",
-                    opt_value=cfg.CONF.default_availability_zones,
+                    opt_value=default_availability_zones,
                     reason=_("The NSX plugin supports only 1 default AZ"))
-            default_az_name = cfg.CONF.default_availability_zones[0]
+            default_az_name = default_availability_zones[0]
             if (default_az_name not in self.availability_zones):
-                if validate_default:
-                    raise nsx_exc.NsxInvalidConfiguration(
-                        opt_name="default_availability_zones",
-                        opt_value=cfg.CONF.default_availability_zones,
-                        reason=_("The default AZ is not defined in the NSX "
-                                 "plugin"))
-                else:
-                    self._default_az = self.availability_zones[
-                        self.default_name]
+                raise nsx_exc.NsxInvalidConfiguration(
+                    opt_name="default_availability_zones",
+                    opt_value=default_availability_zones,
+                    reason=_("The default AZ is not defined in the NSX "
+                             "plugin"))
             else:
                 self._default_az = self.availability_zones[default_az_name]
         else:
diff --git a/vmware_nsx/common/config.py b/vmware_nsx/common/config.py
index 4fb959994f..dd557d1e4b 100644
--- a/vmware_nsx/common/config.py
+++ b/vmware_nsx/common/config.py
@@ -845,6 +845,16 @@ nsx_tvd_opts = [
                choices=projectpluginmap.VALID_TYPES,
                help=_("The default plugin that will be used for new projects "
                       "that were not added to the projects plugin mapping.")),
+    cfg.ListOpt('nsx_v_default_availability_zones',
+                default=[],
+                help=_("The default availability zones that will be used for "
+                       "NSX-V networks and routers creation under the TVD "
+                       "plugin.")),
+    cfg.ListOpt('nsx_v3_default_availability_zones',
+                default=[],
+                help=_("The default availability zones that will be used for "
+                       "NSX-V3 networks and routers creation under the TVD "
+                       "plugin.")),
 ]
 
 # Register the configuration options
diff --git a/vmware_nsx/plugins/nsx/plugin.py b/vmware_nsx/plugins/nsx/plugin.py
index 263c83603e..035b1a5cb3 100644
--- a/vmware_nsx/plugins/nsx/plugin.py
+++ b/vmware_nsx/plugins/nsx/plugin.py
@@ -162,6 +162,9 @@ class NsxTVDPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
         LOG.info("NSX-TVD plugin will use %s as the default plugin",
             self.default_plugin)
 
+        # validate the availability zones configuration
+        self.init_availability_zones()
+
     def get_plugin_by_type(self, plugin_type):
         return self.plugins.get(plugin_type)
 
@@ -192,6 +195,15 @@ class NsxTVDPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
                 self._unsupported_fields[plugin_type]['port'] = [
                     'mac_learning_enabled', 'provider_security_groups']
 
+    def init_availability_zones(self):
+        # Make sure there are no overlaps between v/t availability zones
+        if (self.plugins.get(projectpluginmap.NsxPlugins.NSX_V) and
+            self.plugins.get(projectpluginmap.NsxPlugins.NSX_T) and
+            bool(set(cfg.CONF.nsxv.availability_zones) &
+                 set(cfg.CONF.nsx_v3.availability_zones))):
+            msg = _("Cannot use the same availability zones in NSX-V and T")
+            raise nsx_exc.NsxPluginException(err_msg=msg)
+
     def _unsubscribe_callback_events(self):
         # unsubscribe the callback that should be called on all plugins
         # other that NSX-T.
diff --git a/vmware_nsx/plugins/nsx_v/availability_zones.py b/vmware_nsx/plugins/nsx_v/availability_zones.py
index 4679c27f3a..5e5e759466 100644
--- a/vmware_nsx/plugins/nsx_v/availability_zones.py
+++ b/vmware_nsx/plugins/nsx_v/availability_zones.py
@@ -204,11 +204,15 @@ class NsxVAvailabilityZone(common_az.ConfiguredAvailabilityZone):
 
 class NsxVAvailabilityZones(common_az.ConfiguredAvailabilityZones):
 
-    def __init__(self, validate_default=False):
+    def __init__(self, use_tvd_config=False):
+        if use_tvd_config:
+            default_azs = cfg.CONF.nsx_tvd.nsx_v_default_availability_zones
+        else:
+            default_azs = cfg.CONF.default_availability_zones
         super(NsxVAvailabilityZones, self).__init__(
             cfg.CONF.nsxv.availability_zones,
             NsxVAvailabilityZone,
-            validate_default=validate_default)
+            default_availability_zones=default_azs)
 
     def get_inventory(self):
         """Return a set of relevant resources in all the availability zones
diff --git a/vmware_nsx/plugins/nsx_v/plugin.py b/vmware_nsx/plugins/nsx_v/plugin.py
index 02679825f7..72976e3f90 100644
--- a/vmware_nsx/plugins/nsx_v/plugin.py
+++ b/vmware_nsx/plugins/nsx_v/plugin.py
@@ -1023,9 +1023,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         return '%s.%03d' % (device_id, port_index)
 
     def init_availability_zones(self):
-        validate_default = not self._is_sub_plugin
         self._availability_zones_data = nsx_az.NsxVAvailabilityZones(
-            validate_default=validate_default)
+            use_tvd_config=self._is_sub_plugin)
 
     def _list_availability_zones(self, context, filters=None):
         #TODO(asarfaty): We may need to use the filters arg, but now it
diff --git a/vmware_nsx/plugins/nsx_v3/availability_zones.py b/vmware_nsx/plugins/nsx_v3/availability_zones.py
index 9677d9e770..1e34fa9b53 100644
--- a/vmware_nsx/plugins/nsx_v3/availability_zones.py
+++ b/vmware_nsx/plugins/nsx_v3/availability_zones.py
@@ -210,11 +210,15 @@ class NsxV3AvailabilityZones(common_az.ConfiguredAvailabilityZones):
 
     default_name = DEFAULT_NAME
 
-    def __init__(self, validate_default=False):
+    def __init__(self, use_tvd_config=False):
+        if use_tvd_config:
+            default_azs = cfg.CONF.nsx_tvd.nsx_v3_default_availability_zones
+        else:
+            default_azs = cfg.CONF.default_availability_zones
         super(NsxV3AvailabilityZones, self).__init__(
             cfg.CONF.nsx_v3.availability_zones,
             NsxV3AvailabilityZone,
-            validate_default=validate_default)
+            default_availability_zones=default_azs)
 
     def dhcp_relay_configured(self):
         for az in self.availability_zones.values():
diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py
index f7d094b41f..fa8fd6de4d 100644
--- a/vmware_nsx/plugins/nsx_v3/plugin.py
+++ b/vmware_nsx/plugins/nsx_v3/plugin.py
@@ -375,9 +375,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
             return lb_driver_v2.DummyLoadbalancerDriverV2()
 
     def init_availability_zones(self):
-        validate_default = not self._is_sub_plugin
         self._availability_zones_data = nsx_az.NsxV3AvailabilityZones(
-            validate_default=validate_default)
+            use_tvd_config=self._is_sub_plugin)
 
     def _init_nsx_profiles(self):
         LOG.debug("Initializing NSX v3 port spoofguard switching profile")
@@ -4411,10 +4410,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
             # as the hint (or default if none)
             if hints:
                 az_name = hints[0]
-            elif cfg.CONF.default_availability_zones:
-                az_name = cfg.CONF.default_availability_zones[0]
             else:
-                az_name = nsx_az.DEFAULT_NAME
+                az_name = self.get_default_az().name
             return [az_name]
         else:
             return []
diff --git a/vmware_nsx/tests/unit/nsx_tvd/test_plugin.py b/vmware_nsx/tests/unit/nsx_tvd/test_plugin.py
index 717f02923d..eb2aae385f 100644
--- a/vmware_nsx/tests/unit/nsx_tvd/test_plugin.py
+++ b/vmware_nsx/tests/unit/nsx_tvd/test_plugin.py
@@ -44,6 +44,14 @@ class NsxTVDPluginTestCase(v_tests.NsxVPluginV2TestCase,
             cfg.CONF.set_override('default_plugin', self.plugin_type,
                                   group="nsx_tvd")
 
+        # set the default availability zones
+        cfg.CONF.set_override('nsx_v_default_availability_zones',
+                              ['default'],
+                              group="nsx_tvd")
+        cfg.CONF.set_override('nsx_v3_default_availability_zones',
+                              ['defaultv3'],
+                              group="nsx_tvd")
+
         super(NsxTVDPluginTestCase, self).setUp(
             plugin=plugin,
             ext_mgr=ext_mgr)