From 899b6cb0652ee54c08d130ccd7edc3091b7d930b Mon Sep 17 00:00:00 2001 From: Ann Kamyshnikova Date: Tue, 17 May 2016 17:25:00 +0300 Subject: [PATCH] Pass ha_router_port flag for _snat_router_interfaces ports Currently, router_centralized_snat port can be bound to a host were l3-agent is in standby state (L3 HA + DVR case). As a result VM without floating ip is unable to reach external network. This change passes ha_router_port flag to _ensure_host_set_on_port when called for _snat_router_interfaces ports. Note: this issue is intermittent, without changes in l3_rpc.py unit test does not fail every time. Co-Authored-By: Oleg Bondarev Closes-bug: #1582739 Change-Id: I74bad578361ed7eac8cc6c740b06b66ab1530cd5 --- neutron/api/rpc/handlers/l3_rpc.py | 7 ++-- neutron/tests/unit/db/test_l3_hamode_db.py | 49 +++++++++++++++++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/neutron/api/rpc/handlers/l3_rpc.py b/neutron/api/rpc/handlers/l3_rpc.py index a09528b40cf..74cf58c9fc9 100644 --- a/neutron/api/rpc/handlers/l3_rpc.py +++ b/neutron/api/rpc/handlers/l3_rpc.py @@ -121,9 +121,10 @@ class L3RpcCallback(object): router.get('gw_port'), router['id']) for p in router.get(n_const.SNAT_ROUTER_INTF_KEY, []): - self._ensure_host_set_on_port(context, - gw_port_host, - p, router['id']) + self._ensure_host_set_on_port( + context, gw_port_host, p, router['id'], + ha_router_port=router.get('ha')) + else: self._ensure_host_set_on_port( context, host, diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py index 12c2d8abbfd..cef51c2db84 100644 --- a/neutron/tests/unit/db/test_l3_hamode_db.py +++ b/neutron/tests/unit/db/test_l3_hamode_db.py @@ -29,6 +29,7 @@ from neutron.db import agents_db from neutron.db import common_db_mixin from neutron.db import l3_agentschedulers_db from neutron.db import l3_hamode_db +from neutron.extensions import external_net from neutron.extensions import l3 from neutron.extensions import l3_ext_ha_mode from neutron.extensions import portbindings @@ -914,11 +915,12 @@ class L3HATestCase(L3HATestFramework): class L3HAModeDbTestCase(L3HATestFramework): def _create_network(self, plugin, ctx, name='net', - tenant_id='tenant1'): + tenant_id='tenant1', external=False): network = {'network': {'name': name, 'shared': False, 'admin_state_up': True, - 'tenant_id': tenant_id}} + 'tenant_id': tenant_id, + external_net.EXTERNAL: external}} return plugin.create_network(ctx, network)['id'] def _create_subnet(self, plugin, ctx, network_id, cidr='10.0.0.0/8', @@ -985,6 +987,49 @@ class L3HAModeDbTestCase(L3HATestFramework): port = self._get_first_interface(router['id']) self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID]) + def test_ensure_host_set_on_ports_dvr_ha_binds_to_active(self): + agent3 = helpers.register_l3_agent('host_3', + n_const.L3_AGENT_MODE_DVR_SNAT) + ext_net = self._create_network(self.core_plugin, self.admin_ctx, + external=True) + int_net = self._create_network(self.core_plugin, self.admin_ctx) + subnet = self._create_subnet(self.core_plugin, self.admin_ctx, + int_net) + interface_info = {'subnet_id': subnet['id']} + router = self._create_router(ha=True, distributed=True) + self.plugin._update_router_gw_info(self.admin_ctx, router['id'], + {'network_id': ext_net}) + self.plugin.add_router_interface(self.admin_ctx, + router['id'], + interface_info) + bindings = self.plugin.get_ha_router_port_bindings( + self.admin_ctx, router_ids=[router['id']], + host=self.agent2['host']) + self.plugin._set_router_states(self.admin_ctx, bindings, + {router['id']: 'active'}) + callback = l3_rpc.L3RpcCallback() + callback._l3plugin = self.plugin + # Get router with interfaces + router = self.plugin._get_dvr_sync_data(self.admin_ctx, + self.agent2['host'], + self.agent2, [router['id']])[0] + + callback._ensure_host_set_on_ports(self.admin_ctx, agent3['host'], + [router]) + device_filter = {'device_id': [router['id']], + 'device_owner': + [constants.DEVICE_OWNER_ROUTER_SNAT] + } + port = self.core_plugin.get_ports(self.admin_ctx, + filters=device_filter)[0] + self.assertNotEqual(agent3['host'], port[portbindings.HOST_ID]) + + callback._ensure_host_set_on_ports(self.admin_ctx, + self.agent2['host'], [router]) + port = self.core_plugin.get_ports(self.admin_ctx, + filters=device_filter)[0] + self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID]) + def test_ensure_host_set_on_ports_binds_correctly(self): network_id = self._create_network(self.core_plugin, self.admin_ctx) subnet = self._create_subnet(self.core_plugin, self.admin_ctx,