Cleanup stale metadata processes on l3 agent sync

Currently l3 agent only cleans up stale namespaces.
The fix adds checking and deleting stale metadata processes
to NamespaceManager class responsible for clearing stale
namespaces

Closes-Bug: #1455042

Conflicts:

	neutron/tests/functional/agent/test_l3_agent.py
Change-Id: I2b081803e312589d3d8a7808d286a6c9827ef53f
(cherry picked from commit b058658780)
This commit is contained in:
Oleg Bondarev 2015-05-14 15:09:24 +03:00
parent b4c25d734a
commit c4c8686bc5
5 changed files with 70 additions and 30 deletions

View File

@ -209,10 +209,15 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
continue
break
self.metadata_driver = None
if self.conf.enable_metadata_proxy:
self.metadata_driver = metadata_driver.MetadataDriver(self)
self.namespaces_manager = namespace_manager.NamespaceManager(
self.conf,
self.driver,
self.conf.use_namespaces)
self.conf.use_namespaces,
self.metadata_driver)
self._queue = queue.RouterProcessingQueue()
super(L3NATAgent, self).__init__(conf=self.conf)
@ -220,9 +225,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
self.target_ex_net_id = None
self.use_ipv6 = ipv6_utils.is_enabled()
if self.conf.enable_metadata_proxy:
self.metadata_driver = metadata_driver.MetadataDriver(self)
def _check_config_params(self):
"""Check items in configuration files.

View File

@ -14,6 +14,7 @@ from oslo_log import log as logging
from neutron.agent.l3 import dvr_snat_ns
from neutron.agent.l3 import namespaces
from neutron.agent.linux import external_process
from neutron.agent.linux import ip_lib
from neutron.i18n import _LE
@ -41,16 +42,22 @@ class NamespaceManager(object):
agent restarts gracefully.
"""
def __init__(self, agent_conf, driver, clean_stale):
def __init__(self, agent_conf, driver, clean_stale, metadata_driver=None):
"""Initialize the NamespaceManager.
:param agent_conf: configuration from l3 agent
:param driver: to perform operations on devices
:param clean_stale: Whether to try to clean stale namespaces
:param metadata_driver: used to cleanup stale metadata proxy processes
"""
self.agent_conf = agent_conf
self.driver = driver
self._clean_stale = clean_stale
self.metadata_driver = metadata_driver
if metadata_driver:
self.process_monitor = external_process.ProcessMonitor(
config=agent_conf,
resource_type='router')
def __enter__(self):
self._all_namespaces = set()
@ -85,6 +92,10 @@ class NamespaceManager(object):
self.driver,
use_ipv6=False)
try:
if self.metadata_driver:
# cleanup stale metadata proxy processes first
self.metadata_driver.destroy_monitored_metadata_proxy(
self.process_monitor, ns_id, ns.name, self.agent_conf)
ns.delete()
except RuntimeError:
LOG.exception(_LE('Failed to destroy stale namespace %s'), ns)

View File

@ -31,8 +31,10 @@ class NamespaceManagerTestFramework(base.BaseSudoTestCase):
super(NamespaceManagerTestFramework, self).setUp()
self.agent_conf = mock.MagicMock()
self.agent_conf.router_delete_namespaces = True
self.metadata_driver_mock = mock.Mock()
self.namespace_manager = namespace_manager.NamespaceManager(
self.agent_conf, driver=None, clean_stale=True)
self.agent_conf, driver=None, clean_stale=True,
metadata_driver=self.metadata_driver_mock)
def _create_namespace(self, router_id, ns_class):
namespace = ns_class(router_id, self.agent_conf, driver=None,
@ -59,6 +61,7 @@ class NamespaceManagerTestCase(NamespaceManagerTestFramework):
def test_namespace_manager(self):
router_id = _uuid()
router_id_to_delete = _uuid()
to_keep = set()
to_delete = set()
to_retrieve = set()
@ -66,7 +69,7 @@ class NamespaceManagerTestCase(NamespaceManagerTestFramework):
namespaces.RouterNamespace))
to_keep.add(self._create_namespace(router_id,
dvr_snat_ns.SnatNamespace))
to_delete.add(self._create_namespace(_uuid(),
to_delete.add(self._create_namespace(router_id_to_delete,
dvr_snat_ns.SnatNamespace))
to_retrieve = to_keep | to_delete
@ -80,4 +83,9 @@ class NamespaceManagerTestCase(NamespaceManagerTestFramework):
for ns_name in to_keep:
self.assertTrue(self._namespace_exists(ns_name))
for ns_name in to_delete:
(self.metadata_driver_mock.destroy_monitored_metadata_proxy.
assert_called_once_with(mock.ANY,
router_id_to_delete,
ns_name,
self.agent_conf))
self.assertFalse(self._namespace_exists(ns_name))

View File

@ -62,7 +62,8 @@ def get_ovs_bridge(br_name):
class L3AgentTestFramework(base.BaseOVSLinuxTestCase):
def setUp(self):
super(L3AgentTestFramework, self).setUp()
mock.patch('neutron.agent.l3.agent.L3PluginApi').start()
self.mock_plugin_api = mock.patch(
'neutron.agent.l3.agent.L3PluginApi').start().return_value
self.agent = self._configure_agent('agent1')
def _get_config_opts(self):
@ -507,23 +508,23 @@ class L3AgentTestCase(L3AgentTestFramework):
routers_to_keep = []
routers_to_delete = []
ns_names_to_retrieve = set()
routers_info_to_delete = []
for i in range(2):
routers_to_keep.append(self.generate_router_info(False))
self.manage_router(self.agent, routers_to_keep[i])
ns_names_to_retrieve.add(namespaces.NS_PREFIX +
routers_to_keep[i]['id'])
ri = self.manage_router(self.agent, routers_to_keep[i])
ns_names_to_retrieve.add(ri.ns_name)
for i in range(2):
routers_to_delete.append(self.generate_router_info(False))
self.manage_router(self.agent, routers_to_delete[i])
ns_names_to_retrieve.add(namespaces.NS_PREFIX +
routers_to_delete[i]['id'])
ri = self.manage_router(self.agent, routers_to_delete[i])
routers_info_to_delete.append(ri)
ns_names_to_retrieve.add(ri.ns_name)
# Mock the plugin RPC API to Simulate a situation where the agent
# was handling the 4 routers created above, it went down and after
# starting up again, two of the routers were deleted via the API
mocked_get_routers = (
neutron_l3_agent.L3PluginApi.return_value.get_routers)
mocked_get_routers.return_value = routers_to_keep
self.mock_plugin_api.get_routers.return_value = routers_to_keep
# also clear agent router_info as it will be after restart
self.agent.router_info = {}
# Synchonize the agent with the plug-in
with mock.patch.object(namespace_manager.NamespaceManager, 'list_all',
@ -533,9 +534,8 @@ class L3AgentTestCase(L3AgentTestFramework):
# Mock the plugin RPC API so a known external network id is returned
# when the router updates are processed by the agent
external_network_id = _uuid()
mocked_get_external_network_id = (
neutron_l3_agent.L3PluginApi.return_value.get_external_network_id)
mocked_get_external_network_id.return_value = external_network_id
self.mock_plugin_api.get_external_network_id.return_value = (
external_network_id)
# Plug external_gateway_info in the routers that are not going to be
# deleted by the agent when it processes the updates. Otherwise,
@ -546,7 +546,7 @@ class L3AgentTestCase(L3AgentTestFramework):
# Have the agent process the update from the plug-in and verify
# expected behavior
for _ in routers_to_keep + routers_to_delete:
for _ in routers_to_keep:
self.agent._process_router_update()
for i in range(2):
@ -554,10 +554,9 @@ class L3AgentTestCase(L3AgentTestFramework):
self.assertTrue(self._namespace_exists(namespaces.NS_PREFIX +
routers_to_keep[i]['id']))
for i in range(2):
self.assertNotIn(routers_to_delete[i]['id'],
self.assertNotIn(routers_info_to_delete[i].router_id,
self.agent.router_info)
self.assertFalse(self._namespace_exists(
namespaces.NS_PREFIX + routers_to_delete[i]['id']))
self._assert_router_does_not_exist(routers_info_to_delete[i])
def _router_lifecycle(self, enable_ha, ip_version=4,
dual_stack=False, v6_ext_gw_with_sub=True):
@ -993,15 +992,12 @@ class TestDvrRouter(L3AgentTestFramework):
# gateway_port information before the l3_agent will create it.
# The port returned needs to have the same information as
# router_info['gw_port']
mocked_gw_port = (
neutron_l3_agent.L3PluginApi.return_value.get_agent_gateway_port)
mocked_gw_port.return_value = router_info['gw_port']
self.mock_plugin_api.get_agent_gateway_port.return_value = router_info[
'gw_port']
# We also need to mock the get_external_network_id method to
# get the correct fip namespace.
mocked_ext_net_id = (
neutron_l3_agent.L3PluginApi.return_value.get_external_network_id)
mocked_ext_net_id.return_value = (
self.mock_plugin_api.get_external_network_id.return_value = (
router_info['_floatingips'][0]['floating_network_id'])
# With all that set we can now ask the l3_agent to

View File

@ -445,6 +445,29 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
agent.periodic_sync_routers_task(agent.context)
self.assertFalse(agent.namespaces_manager._clean_stale)
def test_periodic_sync_routers_task_call_clean_stale_meta_proxies(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
stale_router_ids = [_uuid(), _uuid()]
active_routers = [{'id': _uuid()}, {'id': _uuid()}]
self.plugin_api.get_routers.return_value = active_routers
namespace_list = [namespaces.NS_PREFIX + r_id
for r_id in stale_router_ids]
namespace_list += [namespaces.NS_PREFIX + r['id']
for r in active_routers]
self.mock_ip.get_namespaces.return_value = namespace_list
driver = metadata_driver.MetadataDriver
with mock.patch.object(
driver, 'destroy_monitored_metadata_proxy') as destroy_proxy:
agent.periodic_sync_routers_task(agent.context)
expected_calls = [mock.call(mock.ANY,
r_id,
namespaces.NS_PREFIX + r_id,
agent.conf)
for r_id in stale_router_ids]
self.assertEqual(len(stale_router_ids), destroy_proxy.call_count)
destroy_proxy.assert_has_calls(expected_calls, any_order=True)
def test_router_info_create(self):
id = _uuid()
ri = l3router.RouterInfo(id, {}, **self.ri_kwargs)