From 3e6b548984a16e8a272775f5c69468b91e2904ad Mon Sep 17 00:00:00 2001
From: Adit Sarfaty <asarfaty@vmware.com>
Date: Mon, 5 Mar 2018 13:45:15 +0200
Subject: [PATCH] NSX-v3: Add default tier0 router to AZ config

The nsx-v3 plugin can add default Tier-0 router configuration per
availability zone. The Tier-0 rotuer will be used as a default for
external networks creation in this AZ.

Change-Id: I18e917a6b3deb40429626f7f0018e5da7ab72a8b
---
 ...default-tier0-router-2983c6de10dd465a.yaml |  9 +++++++
 vmware_nsx/common/config.py                   |  4 +++
 .../plugins/nsx_v3/availability_zones.py      | 23 ++++++++++++++++
 vmware_nsx/plugins/nsx_v3/plugin.py           | 27 ++++---------------
 .../unit/nsx_v3/test_availability_zones.py    |  9 ++++++-
 5 files changed, 49 insertions(+), 23 deletions(-)
 create mode 100644 releasenotes/notes/nsxv3-default-tier0-router-2983c6de10dd465a.yaml

diff --git a/releasenotes/notes/nsxv3-default-tier0-router-2983c6de10dd465a.yaml b/releasenotes/notes/nsxv3-default-tier0-router-2983c6de10dd465a.yaml
new file mode 100644
index 0000000000..df5c524a84
--- /dev/null
+++ b/releasenotes/notes/nsxv3-default-tier0-router-2983c6de10dd465a.yaml
@@ -0,0 +1,9 @@
+---
+prelude: >
+    The nsx-v3 plugin can add default Tier-0 router configuration per
+    availability zone.
+features:
+  - |
+    The nsx-v3 plugin can add default Tier-0 router configuration per
+    availability zone. The Tier-0 rotuer will be used as a default for
+    external networks creation.
diff --git a/vmware_nsx/common/config.py b/vmware_nsx/common/config.py
index e425aa6966..1ef3f654b0 100644
--- a/vmware_nsx/common/config.py
+++ b/vmware_nsx/common/config.py
@@ -841,6 +841,10 @@ nsxv3_az_opts = [
                help=_("(Optional) This is the name or UUID of the NSX dhcp "
                       "relay service that will be used to enable DHCP relay "
                       "on router ports.")),
+    cfg.StrOpt('default_tier0_router',
+               help=_("Name or UUID of the default tier0 router that will be "
+                      "used for connecting to tier1 logical routers and "
+                      "configuring external networks")),
 ]
 
 nsx_tvd_opts = [
diff --git a/vmware_nsx/plugins/nsx_v3/availability_zones.py b/vmware_nsx/plugins/nsx_v3/availability_zones.py
index 1e34fa9b53..37170012b5 100644
--- a/vmware_nsx/plugins/nsx_v3/availability_zones.py
+++ b/vmware_nsx/plugins/nsx_v3/availability_zones.py
@@ -89,6 +89,10 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone):
         if self.dhcp_relay_service is None:
             self.dhcp_relay_service = cfg.CONF.nsx_v3.dhcp_relay_service
 
+        self.default_tier0_router = az_info.get('default_tier0_router')
+        if self.default_tier0_router is None:
+            self.default_tier0_router = cfg.CONF.nsx_v3.default_tier0_router
+
     def init_default_az(self):
         # use the default configuration
         self.metadata_proxy = cfg.CONF.nsx_v3.metadata_proxy
@@ -100,6 +104,7 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone):
         self.default_vlan_tz = cfg.CONF.nsx_v3.default_vlan_tz
         self.switching_profiles = cfg.CONF.nsx_v3.switching_profiles
         self.dhcp_relay_service = cfg.CONF.nsx_v3.dhcp_relay_service
+        self.default_tier0_router = cfg.CONF.nsx_v3.default_tier0_router
 
     def translate_configured_names_to_uuids(self, nsxlib):
         # Mandatory configurations (in AZ or inherited from global values)
@@ -205,6 +210,24 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone):
             self.dhcp_relay_service = None
             self.dhcp_relay_servers = None
 
+        if self.default_tier0_router:
+            rtr_id = None
+            if cfg.CONF.nsx_v3.init_objects_by_tags:
+                # Find the router by its tag
+                resource_type = (nsxlib.logical_router.resource_type +
+                                 ' AND router_type:TIER0')
+                rtr_id = nsxlib.get_id_by_resource_and_tag(
+                    resource_type,
+                    cfg.CONF.nsx_v3.search_objects_scope,
+                    self.default_tier0_router)
+            if not rtr_id:
+                # find the router by name or id
+                rtr_id = nsxlib.logical_router.get_id_by_name_or_id(
+                    self.default_tier0_router)
+            self._default_tier0_router = rtr_id
+        else:
+            self._default_tier0_router = None
+
 
 class NsxV3AvailabilityZones(common_az.ConfiguredAvailabilityZones):
 
diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py
index f2b7eb5c33..6ed47b76ba 100644
--- a/vmware_nsx/plugins/nsx_v3/plugin.py
+++ b/vmware_nsx/plugins/nsx_v3/plugin.py
@@ -439,24 +439,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
             raise cfg.RequiredOptError("search_objects_scope",
                                        group=cfg.OptGroup('nsx_v3'))
 
-        # default tier0 router
-        self._default_tier0_router = None
-        if cfg.CONF.nsx_v3.default_tier0_router:
-            rtr_id = None
-            if cfg.CONF.nsx_v3.init_objects_by_tags:
-                # Find the router by its tag
-                resource_type = (self.nsxlib.logical_router.resource_type +
-                                 ' AND router_type:TIER0')
-                rtr_id = self.nsxlib.get_id_by_resource_and_tag(
-                    resource_type,
-                    cfg.CONF.nsx_v3.search_objects_scope,
-                    cfg.CONF.nsx_v3.default_tier0_router)
-            if not rtr_id:
-                # find the router by name or id
-                rtr_id = self.nsxlib.logical_router.get_id_by_name_or_id(
-                    cfg.CONF.nsx_v3.default_tier0_router)
-            self._default_tier0_router = rtr_id
-
         # Validate and translate native dhcp profiles per az
         if cfg.CONF.nsx_v3.native_dhcp_metadata:
             if not cfg.CONF.nsx_v3.dhcp_profile:
@@ -905,9 +887,9 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
         tier0_info = self.tier0_groups_dict[tier0_uuid]
         return tier0_info['edge_cluster_uuid']
 
-    def _validate_external_net_create(self, net_data):
+    def _validate_external_net_create(self, net_data, az):
         if not validators.is_attr_set(net_data.get(pnet.PHYSICAL_NETWORK)):
-            tier0_uuid = self._default_tier0_router
+            tier0_uuid = az._default_tier0_router
         else:
             tier0_uuid = net_data[pnet.PHYSICAL_NETWORK]
         if ((validators.is_attr_set(net_data.get(pnet.NETWORK_TYPE)) and
@@ -1090,7 +1072,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
         if validators.is_attr_set(external) and external:
             self._assert_on_external_net_with_qos(net_data)
             is_provider_net, net_type, physical_net, vlan_id = (
-                self._validate_external_net_create(net_data))
+                self._validate_external_net_create(net_data, az))
         else:
             is_provider_net, net_type, physical_net, vlan_id, nsx_net_id = (
                 self._create_network_at_the_backend(context, net_data, az,
@@ -3184,7 +3166,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
             return
         network = self.get_network(context, network_id)
         if not network.get(pnet.PHYSICAL_NETWORK):
-            return self._default_tier0_router
+            az = self.get_network_az_by_net_id(context, network_id)
+            return az._default_tier0_router
         else:
             return network.get(pnet.PHYSICAL_NETWORK)
 
diff --git a/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py b/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py
index 04330bbf66..a2e41ad338 100644
--- a/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py
+++ b/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py
@@ -42,6 +42,8 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase):
         cfg.CONF.set_override("nameservers", ["10.1.1.1"], group="nsx_v3")
         cfg.CONF.set_override("switching_profiles", ["uuid1"], group="nsx_v3")
         cfg.CONF.set_override("dhcp_relay_service", "service1", group="nsx_v3")
+        cfg.CONF.set_override(
+            "default_tier0_router", "uuidrtr1", group="nsx_v3")
 
     def _config_az(self,
                    metadata_proxy="metadata_proxy1",
@@ -52,7 +54,8 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase):
                    default_overlay_tz='otz',
                    default_vlan_tz='vtz',
                    switching_profiles=["uuid2"],
-                   dhcp_relay_service="service2"):
+                   dhcp_relay_service="service2",
+                   default_tier0_router="uuidrtr2"):
         if metadata_proxy is not None:
             cfg.CONF.set_override("metadata_proxy", metadata_proxy,
                                   group=self.group_name)
@@ -81,6 +84,9 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase):
         if dhcp_relay_service is not None:
             cfg.CONF.set_override("dhcp_relay_service", dhcp_relay_service,
                                   group=self.group_name)
+        if default_tier0_router is not None:
+            cfg.CONF.set_override("default_tier0_router", default_tier0_router,
+                                  group=self.group_name)
 
     def test_simple_availability_zone(self):
         self._config_az()
@@ -95,6 +101,7 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase):
         self.assertEqual("vtz", az.default_vlan_tz)
         self.assertEqual(["uuid2"], az.switching_profiles)
         self.assertEqual("service2", az.dhcp_relay_service)
+        self.assertEqual("uuidrtr2", az.default_tier0_router)
 
     def test_missing_group_section(self):
         self.assertRaises(