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 Change-Id: I2b081803e312589d3d8a7808d286a6c9827ef53f Closes-Bug: #1455042
This commit is contained in:
parent
4e34dded69
commit
b058658780
|
@ -208,10 +208,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)
|
||||
|
@ -219,9 +224,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.
|
||||
|
||||
|
|
|
@ -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, self.agent_conf)
|
||||
ns.delete()
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('Failed to destroy stale namespace %s'), ns)
|
||||
|
|
|
@ -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,8 @@ 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,
|
||||
self.agent_conf))
|
||||
self.assertFalse(self._namespace_exists(ns_name))
|
||||
|
|
|
@ -63,7 +63,8 @@ def get_ovs_bridge(br_name):
|
|||
class L3AgentTestFramework(base.BaseSudoTestCase):
|
||||
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
|
||||
mock.patch('neutron.agent.rpc.PluginReportStateAPI').start()
|
||||
self.agent = self._configure_agent('agent1')
|
||||
|
||||
|
@ -500,23 +501,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',
|
||||
|
@ -526,9 +527,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,
|
||||
|
@ -539,7 +539,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):
|
||||
|
@ -547,10 +547,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):
|
||||
|
@ -948,9 +947,7 @@ class TestDvrRouter(L3AgentTestFramework):
|
|||
self, agent_mode, **dvr_router_kwargs):
|
||||
self.agent.conf.agent_mode = agent_mode
|
||||
router_info = self.generate_dvr_router_info(**dvr_router_kwargs)
|
||||
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'])
|
||||
router = self.manage_router(self.agent, router_info)
|
||||
fip_ns = router.fip_ns.get_name()
|
||||
|
@ -1010,15 +1007,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
|
||||
|
|
|
@ -426,6 +426,26 @@ 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, 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)
|
||||
|
|
Loading…
Reference in New Issue