From d77a0f25658d1a07712ea4854b92bc7a4d9507a0 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Wed, 16 Jan 2019 12:06:34 +0200 Subject: [PATCH] NSX|V3+P: Set router standby relocation when creating service router The NSX backend does not support this flag without a service router any more, so setting this flag will be done when creating the service router, and it will be unset when removing the service router. Change-Id: Iea4ea637359783c0d1de9b89b96135b63900ae26 --- vmware_nsx/plugins/nsx_p/plugin.py | 29 ++++--- vmware_nsx/plugins/nsx_v3/plugin.py | 23 +++-- .../admin/plugins/nsxv3/resources/routers.py | 14 ++- vmware_nsx/tests/unit/nsx_v3/test_plugin.py | 86 +++++++++---------- 4 files changed, 88 insertions(+), 64 deletions(-) diff --git a/vmware_nsx/plugins/nsx_p/plugin.py b/vmware_nsx/plugins/nsx_p/plugin.py index 32e3548822..f31e1132d9 100644 --- a/vmware_nsx/plugins/nsx_p/plugin.py +++ b/vmware_nsx/plugins/nsx_p/plugin.py @@ -1064,6 +1064,7 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base): tier0_uuid) def create_service_router(self, context, router_id): + """Create a service router and enable standby relocation""" router = self._get_router(context, router_id) tier0_uuid = self._get_tier0_uuid_by_router(context, router) edge_cluster_path = self._get_edge_cluster_path( @@ -1075,7 +1076,25 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base): LOG.error("Tier0 %s does not have an edge cluster", tier0_uuid) + if cfg.CONF.nsx_p.allow_passthrough: + try: + # Enable standby relocation on this router + self.nsxpolicy.tier1.set_standby_relocation( + router['id'], enable_standby_relocation=True) + except Exception as ex: + LOG.warning("Failed to enable standby relocation for router " + "%s: %s", router['id'], ex) + def delete_service_router(self, router_id): + if cfg.CONF.nsx_p.allow_passthrough: + try: + # Enable standby relocation on this router + self.nsxpolicy.tier1.set_standby_relocation( + router_id, enable_standby_relocation=False) + except Exception as ex: + LOG.warning("Failed to disable standby relocation for router " + "%s: %s", router_id, ex) + # remove the edge cluster from the tier1 router self.nsxpolicy.tier1.remove_edge_cluster(router_id) @@ -1200,16 +1219,6 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base): "DB and backend", router['id']) - if cfg.CONF.nsx_p.allow_passthrough: - try: - # Enable standby relocation on this router - self.nsxpolicy.tier1.set_standby_relocation( - router['id'], - enable_standby_relocation=True) - except Exception as ex: - LOG.warning("Failed to enable standby relocation for router " - "%s: %s", router['id'], ex) - return self.get_router(context, router['id']) def delete_router(self, context, router_id): diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 210abeafa9..4b2bc09a67 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -2110,20 +2110,31 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, return snat_exist or lb_exist or fw_exist def create_service_router(self, context, router_id): + """Create a service router and enable standby relocation""" router = self._get_router(context, router_id) tier0_uuid = self._get_tier0_uuid_by_router(context, router) edge_cluster_uuid = self._get_edge_cluster(tier0_uuid, router) nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) - self.nsxlib.router.update_router_edge_cluster(nsx_router_id, - edge_cluster_uuid) + enable_standby_relocation = False + if self.nsxlib.feature_supported( + nsxlib_consts.FEATURE_ROUTER_ALLOCATION_PROFILE): + enable_standby_relocation = True + + self.nsxlib.logical_router.update( + nsx_router_id, + edge_cluster_id=edge_cluster_uuid, + enable_standby_relocation=enable_standby_relocation) def delete_service_router(self, context, router_id): nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) self.nsxlib.router.change_edge_firewall_status( nsx_router_id, nsxlib_consts.FW_DISABLE) - self.nsxlib.router.update_router_edge_cluster(nsx_router_id, None) + self.nsxlib.logical_router.update( + nsx_router_id, + edge_cluster_id=None, + enable_standby_relocation=False) def _update_router_gw_info(self, context, router_id, info): router = self._get_router(context, router_id) @@ -2272,10 +2283,6 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, self._add_az_to_router(context, router['id'], r) router_db = self._get_router(context, r['id']) - enable_standby_relocation = False - if self.nsxlib.feature_supported( - nsxlib_consts.FEATURE_ROUTER_ALLOCATION_PROFILE): - enable_standby_relocation = True with db_api.CONTEXT_WRITER.using(context): self._process_extra_attr_router_create(context, router_db, r) # Create backend entries here in case neutron DB exception @@ -2286,7 +2293,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, display_name=utils.get_name_and_uuid( router['name'] or 'router', router['id']), description=router.get('description'), - tags=tags, enable_standby_relocation=enable_standby_relocation) + tags=tags) except nsx_lib_exc.ManagerError: with excutils.save_and_reraise_exception(): LOG.error("Unable to create logical router for " diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py index 89a84ec0d8..52427c4959 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py @@ -135,9 +135,17 @@ def update_enable_standby_relocation(resource, event, trigger, **kwargs): # get the router nsx id from the mapping table nsx_id = nsx_db.get_nsx_router_id(admin_cxt.session, neutron_id) - nsxlib.logical_router.update(lrouter_id=nsx_id, - enable_standby_relocation=True) - LOG.info("All routers where enabled with standby relocation") + try: + nsxlib.logical_router.update(lrouter_id=nsx_id, + enable_standby_relocation=True) + except Exception as e: + # This may fail if the service router is not created + LOG.warning("Router %s cannot enable standby relocation: %s", + neutron_id, e) + else: + LOG.info("Router %s was enabled with standby relocation", + neutron_id) + LOG.info("Done") @admin_utils.output_header diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index aa99cf2796..a41eaa3ca6 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -72,6 +72,7 @@ NSX_DHCP_PROFILE_ID = 'default dhcp profile' NSX_METADATA_PROXY_ID = 'default metadata proxy' NSX_SWITCH_PROFILE = 'dummy switch profile' NSX_DHCP_RELAY_SRV = 'dhcp relay srv' +NSX_EDGE_CLUSTER_UUID = 'dummy edge cluster' def _mock_create_firewall_rules(*args): @@ -175,7 +176,7 @@ def _mock_nsx_backend_calls(): mock.patch( "vmware_nsxlib.v3.NsxLib.get_version", - return_value='2.2.0').start() + return_value='2.4.0').start() mock.patch( "vmware_nsxlib.v3.load_balancer.Service.get_router_lb_service", @@ -220,7 +221,7 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase, self.setup_conf_overrides() self.mock_get_edge_cluster = mock.patch.object( nsx_plugin.NsxV3Plugin, '_get_edge_cluster', - return_value=uuidutils.generate_uuid()) + return_value=NSX_EDGE_CLUSTER_UUID) self.mock_get_edge_cluster.start() self.mock_plugin_methods() # ignoring the given plugin and use the nsx-v3 one @@ -517,11 +518,12 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin): def test_create_ens_network_with_port_sec(self): cfg.CONF.set_override('ens_support', True, 'nsx_v3') providernet_args = {psec.PORTSECURITY: True} - with mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." - "get_host_switch_mode", return_value="ENS"),\ - mock.patch( - "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", - return_value={'transport_zone_id': 'xxx'}): + with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.3.0'),\ + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." + "get_host_switch_mode", return_value="ENS"),\ + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch." + "get", return_value={'transport_zone_id': 'xxx'}): result = self._create_network(fmt='json', name='ens_net', admin_state_up=True, providernet_args=providernet_args, @@ -534,13 +536,10 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin): def test_create_ens_network_with_port_sec_supported(self): cfg.CONF.set_override('ens_support', True, 'nsx_v3') providernet_args = {psec.PORTSECURITY: True} - with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", - return_value='2.4.0'),\ - mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." + with mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." "get_host_switch_mode", return_value="ENS"),\ - mock.patch( - "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", - return_value={'transport_zone_id': 'xxx'}): + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch." + "get", return_value={'transport_zone_id': 'xxx'}): result = self._create_network(fmt='json', name='ens_net', admin_state_up=True, providernet_args=providernet_args, @@ -636,12 +635,12 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin): def test_update_ens_network(self): cfg.CONF.set_override('ens_support', True, 'nsx_v3') providernet_args = {psec.PORTSECURITY: False} - with mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." - "get_host_switch_mode", return_value="ENS"),\ - mock.patch( - "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", - return_value={'transport_zone_id': 'xxx'}): - + with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.3.0'),\ + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." + "get_host_switch_mode", return_value="ENS"),\ + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch." + "get", return_value={'transport_zone_id': 'xxx'}): result = self._create_network(fmt='json', name='ens_net', admin_state_up=True, providernet_args=providernet_args, @@ -659,10 +658,8 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin): def test_update_ens_network_psec_supported(self): cfg.CONF.set_override('ens_support', True, 'nsx_v3') providernet_args = {psec.PORTSECURITY: False} - with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", - return_value='2.4.0'),\ - mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." - "get_host_switch_mode", return_value="ENS"),\ + with mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." + "get_host_switch_mode", return_value="ENS"),\ mock.patch( "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", return_value={'transport_zone_id': 'xxx'}): @@ -1595,11 +1592,12 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, def test_create_ens_port_with_port_sec(self): with self.subnet() as subnet,\ + mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.3.0'),\ mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." "get_host_switch_mode", return_value="ENS"),\ - mock.patch( - "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", - return_value={'transport_zone_id': 'xxx'}): + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch." + "get", return_value={'transport_zone_id': 'xxx'}): args = {'port': {'network_id': subnet['subnet']['network_id'], 'tenant_id': subnet['subnet']['tenant_id'], 'fixed_ips': [{'subnet_id': @@ -1613,8 +1611,6 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, def test_create_ens_port_with_port_sec_supported(self): with self.subnet() as subnet,\ - mock.patch("vmware_nsxlib.v3.NsxLib.get_version", - return_value='2.4.0'),\ mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." "get_host_switch_mode", return_value="ENS"),\ mock.patch( @@ -1632,11 +1628,12 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, def test_update_ens_port(self): with self.subnet() as subnet,\ + mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.3.0'),\ mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." "get_host_switch_mode", return_value="ENS"),\ - mock.patch( - "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", - return_value={'transport_zone_id': 'xxx'}): + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch." + "get", return_value={'transport_zone_id': 'xxx'}): args = {'port': {'network_id': subnet['subnet']['network_id'], 'tenant_id': subnet['subnet']['tenant_id'], 'fixed_ips': [{'subnet_id': @@ -1654,13 +1651,10 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, def test_update_ens_port_psec_supported(self): with self.subnet() as subnet,\ - mock.patch("vmware_nsxlib.v3.NsxLib.get_version", - return_value='2.4.0'),\ mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone." "get_host_switch_mode", return_value="ENS"),\ - mock.patch( - "vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get", - return_value={'transport_zone_id': 'xxx'}): + mock.patch("vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch." + "get", return_value={'transport_zone_id': 'xxx'}): args = {'port': {'network_id': subnet['subnet']['network_id'], 'tenant_id': subnet['subnet']['tenant_id'], 'fixed_ips': [{'subnet_id': @@ -2596,8 +2590,8 @@ class TestL3NatTestCase(L3NatTest, "add_gw_snat_rule") def _mock_add_remove_service_router(self): - return mock.patch("vmware_nsxlib.v3.router.RouterLib." - "update_router_edge_cluster") + return mock.patch("vmware_nsxlib.v3.core_resources." + "NsxLibLogicalRouter.update") def _mock_del_snat_rule(self): return mock.patch("vmware_nsxlib.v3.router.RouterLib." @@ -2668,9 +2662,11 @@ class TestL3NatTestCase(L3NatTest, router_id = r['router']['id'] self._add_external_gateway_to_router( router_id, ext_subnet['network_id']) - # Checking that update_edge_cluster is being called with + # Checking that router update is being called with # edge_cluster_uuid, for creating a service router - self.assertIsNotNone(change_sr.call_args_list[0][0][1]) + change_sr.assert_called_once_with( + mock.ANY, edge_cluster_id=NSX_EDGE_CLUSTER_UUID, + enable_standby_relocation=True) def test_remove_service_router_disable_snat(self): with self.address_scope(name='as1') as addr_scope, \ @@ -2688,10 +2684,12 @@ class TestL3NatTestCase(L3NatTest, r['router']['id'], ext_subnet['network_id'], False) - # Checking that update_edge_cluster is being called + # Checking that router update is being called # and setting edge_cluster_uuid to None, for service # router removal. - self.assertIsNone(change_sr.call_args_list[0][0][1]) + change_sr.assert_called_once_with( + mock.ANY, edge_cluster_id=None, + enable_standby_relocation=False) def test_router_address_scope_snat_rules(self): """Test that if the router interface had the same address scope @@ -3026,7 +3024,9 @@ class TestL3NatTestCase(L3NatTest, router_id = r['router']['id'] self._add_external_gateway_to_router( router_id, ext_subnet['network_id']) - change_sr.assert_called_once_with(mock.ANY, edge_cluster) + change_sr.assert_called_once_with( + mock.ANY, edge_cluster_id=edge_cluster, + enable_standby_relocation=True) self.mock_get_edge_cluster.start()