Fix migration from the HA to non-HA routers
In case if during switching HA router to be down, there will be any failure, router_info will be stored in L3 agent's cache as HaRouter. In case when next update on the router is migration to non-HA router this is wrong class and it causes other issues, e.g. with remove_vip_by_ip_address() which is correct only for HA routers. This patch fixes that issue by adding check of the router's ha and distributed flags and update local cache with new router_info class in case if at least one of those flags don't match. Change-Id: Ib0d3a501f88c149baea7d715c7cfe5811bc85e4f Closes-Bug: #1892846
This commit is contained in:
parent
b207f05ba7
commit
489e0ead72
|
@ -626,6 +626,23 @@ class L3NATAgent(ha.AgentMixin,
|
|||
|
||||
def _process_updated_router(self, router):
|
||||
ri = self.router_info[router['id']]
|
||||
|
||||
router_ha = router.get('ha')
|
||||
router_distributed = router.get('distributed')
|
||||
if ((router_ha is not None and ri.router.get('ha') != router_ha) or
|
||||
(router_distributed is not None and
|
||||
ri.router.get('distributed') != router_distributed)):
|
||||
LOG.warning('Type of the router %(id)s changed. '
|
||||
'Old type: ha=%(old_ha)s; distributed=%(old_dvr)s; '
|
||||
'New type: ha=%(new_ha)s; distributed=%(new_dvr)s',
|
||||
{'id': router['id'],
|
||||
'old_ha': ri.router.get('ha'),
|
||||
'old_dvr': ri.router.get('distributed'),
|
||||
'new_ha': router.get('ha'),
|
||||
'new_dvr': router.get('distributed')})
|
||||
ri = self._create_router(router['id'], router)
|
||||
self.router_info[router['id']] = ri
|
||||
|
||||
is_dvr_snat_agent = (self.conf.agent_mode ==
|
||||
lib_const.L3_AGENT_MODE_DVR_SNAT)
|
||||
is_dvr_only_agent = (self.conf.agent_mode in
|
||||
|
|
|
@ -2858,6 +2858,16 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
router.distributed = True
|
||||
router.ha = True
|
||||
router_info = mock.MagicMock()
|
||||
|
||||
def mock_get(name):
|
||||
if name == 'ha':
|
||||
return router.ha
|
||||
if name == 'distributed':
|
||||
return router.distributed
|
||||
return mock.Mock()
|
||||
|
||||
router_info.router.get.side_effect = mock_get
|
||||
|
||||
agent.router_info[router.id] = router_info
|
||||
updated_router = {'id': '1234',
|
||||
'distributed': True,
|
||||
|
@ -2890,6 +2900,16 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
router._ha_interface = True
|
||||
router.ha = True
|
||||
router_info = mock.MagicMock()
|
||||
|
||||
def mock_get(name):
|
||||
if name == 'ha':
|
||||
return router.ha
|
||||
if name == 'distributed':
|
||||
return router.distributed
|
||||
return mock.Mock()
|
||||
|
||||
router_info.router.get.side_effect = mock_get
|
||||
|
||||
agent.router_info[router.id] = router_info
|
||||
updated_router = {'id': '1234',
|
||||
'distributed': True, 'ha': True,
|
||||
|
@ -2954,6 +2974,46 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
agent._process_router_if_compatible(router)
|
||||
self.assertIn(router['id'], agent.router_info)
|
||||
|
||||
def test_process_router_if_compatible_type_match(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
|
||||
router = {'id': _uuid(),
|
||||
'routes': [],
|
||||
'admin_state_up': True,
|
||||
'ha': False, 'distributed': False,
|
||||
'external_gateway_info': {'network_id': 'aaa'}}
|
||||
|
||||
ri = mock.Mock(router=router)
|
||||
agent.router_info[router['id']] = ri
|
||||
with mock.patch.object(agent, "_create_router") as create_router_mock:
|
||||
agent._process_router_if_compatible(router)
|
||||
create_router_mock.assert_not_called()
|
||||
self.assertIn(router['id'], agent.router_info)
|
||||
self.assertFalse(agent.router_info[router['id']].router['ha'])
|
||||
self.assertFalse(agent.router_info[router['id']].router['distributed'])
|
||||
|
||||
def test_process_router_if_compatible_type_changed(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
|
||||
router = {'id': _uuid(),
|
||||
'routes': [],
|
||||
'admin_state_up': True,
|
||||
'revision_number': 1,
|
||||
'ha': True, 'distributed': False,
|
||||
'external_gateway_info': {'network_id': 'aaa'}}
|
||||
|
||||
ri = mock.Mock(router=router)
|
||||
agent.router_info[router['id']] = ri
|
||||
new_router = copy.deepcopy(router)
|
||||
new_router['ha'] = False
|
||||
with mock.patch.object(agent, "_create_router") as create_router_mock:
|
||||
agent._process_router_if_compatible(new_router)
|
||||
create_router_mock.assert_called_once_with(
|
||||
new_router['id'], new_router)
|
||||
self.assertIn(router['id'], agent.router_info)
|
||||
self.assertFalse(agent.router_info[router['id']].router['ha'])
|
||||
self.assertFalse(agent.router_info[router['id']].router['distributed'])
|
||||
|
||||
def test_nonexistent_interface_driver(self):
|
||||
self.conf.set_override('interface_driver', None)
|
||||
self.assertRaises(SystemExit, l3_agent.L3NATAgent,
|
||||
|
|
Loading…
Reference in New Issue