diff --git a/neutron/agent/l3_agent.py b/neutron/agent/l3_agent.py index a3d156f417..62c7d1155f 100644 --- a/neutron/agent/l3_agent.py +++ b/neutron/agent/l3_agent.py @@ -1399,6 +1399,8 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, def external_gateway_removed(self, ri, ex_gw_port, interface_name): if ri.router['distributed']: + self.process_router_floating_ip_nat_rules(ri) + self.process_router_floating_ip_addresses(ri, ex_gw_port) for p in ri.internal_ports: internal_interface = self.get_internal_device_name(p['id']) self._snat_redirect_remove(ri, p, internal_interface) diff --git a/neutron/tests/unit/test_l3_agent.py b/neutron/tests/unit/test_l3_agent.py index 7c692fa360..54ae156cf6 100644 --- a/neutron/tests/unit/test_l3_agent.py +++ b/neutron/tests/unit/test_l3_agent.py @@ -44,6 +44,11 @@ FAKE_ID_2 = _uuid() FIP_PRI = 32768 +class FakeDev(object): + def __init__(self, name): + self.name = name + + class TestExclusiveRouterProcessor(base.BaseTestCase): def setUp(self): super(TestExclusiveRouterProcessor, self).setUp() @@ -1030,8 +1035,11 @@ class TestBasicRouterOperations(base.BaseTestCase): del router['gw_port'] agent.process_router(ri) self.assertEqual(self.send_arp.call_count, 1) - self.assertFalse(agent.process_router_floating_ip_addresses.called) - self.assertFalse(agent.process_router_floating_ip_nat_rules.called) + distributed = ri.router.get('distributed', False) + self.assertEqual(agent.process_router_floating_ip_addresses.called, + distributed) + self.assertEqual(agent.process_router_floating_ip_nat_rules.called, + distributed) def test_ha_router_keepalived_config(self): agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) @@ -1639,10 +1647,6 @@ vrrp_instance VR_1 { matchers.LessThan(nat_rules.index(snat_rule))) def test_process_router_delete_stale_internal_devices(self): - class FakeDev(object): - def __init__(self, name): - self.name = name - agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) stale_devlist = [FakeDev('qr-a1b2c3d4-e5'), FakeDev('qr-b2c3d4e5-f6')] @@ -1690,10 +1694,6 @@ vrrp_instance VR_1 { self.mock_driver.unplug.assert_has_calls(calls, any_order=True) def test_process_router_delete_stale_external_devices(self): - class FakeDev(object): - def __init__(self, name): - self.name = name - agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) stale_devlist = [FakeDev('qg-a1b2c3d4-e5')] stale_devnames = [dev.name for dev in stale_devlist] @@ -1739,10 +1739,6 @@ vrrp_instance VR_1 { self.assertEqual(1, agent._queue.add.call_count) def test_destroy_fip_namespace(self): - class FakeDev(object): - def __init__(self, name): - self.name = name - namespaces = ['qrouter-foo', 'qrouter-bar'] self.mock_ip.get_namespaces.return_value = namespaces @@ -1760,10 +1756,6 @@ vrrp_instance VR_1 { self.mock_ip.del_veth.assert_called_once_with('fpr-aaaa') def test_destroy_namespace(self): - class FakeDev(object): - def __init__(self, name): - self.name = name - namespace = 'qrouter-bar' self.mock_ip.get_namespaces.return_value = [namespace] @@ -2266,6 +2258,63 @@ vrrp_instance VR_1 { self.assertFalse(is_last) self.assertEqual(len(agent.fip_ns_subscribers), 1) + def test_external_gateway_removed_ext_gw_port_and_fip(self): + self.conf.set_override('state_path', '/tmp') + self.conf.set_override('router_delete_namespaces', True) + + agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) + agent.conf.agent_mode = 'dvr' + agent.agent_gateway_port = {'fixed_ips': [{'ip_address': '20.0.0.30', + 'subnet_id': _uuid()}], + 'subnet': {'gateway_ip': '20.0.0.1'}, + 'id': _uuid(), + 'network_id': _uuid(), + 'mac_address': 'ca:fe:de:ad:be:ef', + 'ip_cidr': '20.0.0.30/24'} + external_net_id = _uuid() + agent._fetch_external_net_id = mock.Mock(return_value=external_net_id) + + router = prepare_router_data(num_internal_ports=2) + router['distributed'] = True + router['gw_port_host'] = HOSTNAME + + ri = l3_agent.RouterInfo(router['id'], self.conf.root_helper, router) + vm_floating_ip = '19.4.4.2' + ri.floating_ips_dict[vm_floating_ip] = FIP_PRI + ri.dist_fip_count = 1 + ri.ex_gw_port = ri.router['gw_port'] + del ri.router['gw_port'] + ri.rtr_fip_subnet = agent.local_subnets.allocate(ri.router_id) + _, fip_to_rtr = ri.rtr_fip_subnet.get_pair() + nat = ri.iptables_manager.ipv4['nat'] + nat.clear_rules_by_tag = mock.Mock() + nat.add_rule = mock.Mock() + + self.mock_ip.get_devices.return_value = [ + FakeDev(agent.get_fip_ext_device_name(_uuid()))] + self.mock_ip_dev.addr.list.return_value = [ + {'cidr': vm_floating_ip + '/32'}, + {'cidr': '19.4.4.1/24'}] + self.device_exists.return_value = True + + agent.external_gateway_removed( + ri, ri.ex_gw_port, + agent.get_external_device_name(ri.ex_gw_port['id'])) + + self.mock_ip.del_veth.assert_called_once_with( + agent.get_fip_int_device_name(ri.router['id'])) + self.mock_ip_dev.route.delete_gateway.assert_called_once_with( + str(fip_to_rtr.ip), table=l3_agent.FIP_RT_TBL) + + self.assertEqual(ri.dist_fip_count, 0) + self.assertEqual(len(agent.fip_ns_subscribers), 0) + self.assertEqual(self.mock_driver.unplug.call_count, 1) + self.assertIsNone(agent.agent_gateway_port) + self.mock_ip.netns.delete.assert_called_once_with( + agent.get_fip_ns_name(external_net_id)) + self.assertFalse(nat.add_rule.called) + nat.clear_rules_by_tag.assert_called_once_with('floating_ip') + class TestL3AgentEventHandler(base.BaseTestCase):