Fix l3 agent to not create already deleted router

In case router is deleted during l3 agent resync,
the "deleted" event is processed with higher priority, then
resync event for the router may be processed which will recreate
already deleted router.
This happens due to timestamp not being properly updated for deleted
router in router processor.
The fix adds timestamp update for deleted router.

Functional test will be updated in a follow-up patch

Logging was improved to make debugging a bit easier.

Closes-Bug: #1455439
Change-Id: I2d060064acccc10591a3d90be9011f116548cfce
This commit is contained in:
Oleg Bondarev 2015-06-11 13:38:55 +03:00
parent 4d35f15265
commit 74b0c53da5
2 changed files with 25 additions and 1 deletions

View File

@ -441,7 +441,8 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
def _process_router_update(self):
for rp, update in self._queue.each_update_to_next_router():
LOG.debug("Starting router update for %s", update.id)
LOG.debug("Starting router update for %s, action %s, priority %s",
update.id, update.action, update.priority)
router = update.router
if update.action != queue.DELETE_ROUTER and not router:
try:
@ -464,6 +465,12 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
# one router by sticking the update at the end of the queue
# at a lower priority.
self.fullsync = True
else:
# need to update timestamp of removed router in case
# there are older events for the same router in the
# processing queue (like events from fullsync) in order to
# prevent deleted router re-creation
rp.fetched_and_processed(update.timestamp)
continue
try:

View File

@ -2090,6 +2090,23 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
agent._process_router_update()
self.assertTrue(agent.fullsync)
def test_process_routers_update_router_deleted(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent._queue = mock.Mock()
update = mock.Mock()
update.router = None
update.action = 1 # ROUTER_DELETED
router_info = mock.MagicMock()
agent.router_info[update.id] = router_info
router_processor = mock.Mock()
agent._queue.each_update_to_next_router.side_effect = [
[(router_processor, update)]]
agent._process_router_update()
router_info.delete.assert_called_once_with(agent)
self.assertFalse(agent.router_info)
router_processor.fetched_and_processed.assert_called_once_with(
update.timestamp)
def test_process_router_if_compatible_with_no_ext_net_in_conf(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.plugin_api.get_external_network_id.return_value = 'aaa'