diff --git a/neutron/agent/l3/ha_router.py b/neutron/agent/l3/ha_router.py index 2a8e4f6aacd..c5476c3c0b6 100644 --- a/neutron/agent/l3/ha_router.py +++ b/neutron/agent/l3/ha_router.py @@ -450,10 +450,18 @@ class HaRouter(router.RouterInfo): pm.enable() process_monitor.register( self.router_id, IP_MONITOR_PROCESS_SERVICE, pm) - LOG.debug("Router %(router_id)s %(process)s pid %(pid)d", - {"router_id": self.router_id, - "process": KEEPALIVED_STATE_CHANGE_MONITOR_SERVICE_NAME, - "pid": pm.pid}) + pid = pm.pid + process = KEEPALIVED_STATE_CHANGE_MONITOR_SERVICE_NAME + if pid: + LOG.debug("Router %(router_id)s %(process)s pid %(pid)d", + {"router_id": self.router_id, + "process": process, + "pid": pid}) + else: + LOG.warning("Could not determine pid for router %(router_id)s " + "%(process)s, might still be spawning", + {"router_id": self.router_id, + "process": process}) def destroy_state_change_monitor(self, process_monitor): if not self.ha_port: diff --git a/neutron/tests/unit/agent/l3/test_ha_router.py b/neutron/tests/unit/agent/l3/test_ha_router.py index 95ee5ef8c5d..15045448a72 100644 --- a/neutron/tests/unit/agent/l3/test_ha_router.py +++ b/neutron/tests/unit/agent/l3/test_ha_router.py @@ -127,6 +127,34 @@ class TestBasicRouterOperations(base.BaseTestCase): ri.remove_floating_ip(device, fip_cidr) self.assertTrue(super_remove_floating_ip.called) + @mock.patch.object(ha_router.LOG, 'debug') + def test_spawn_state_change_monitor(self, mock_log): + ri = self._create_router(mock.MagicMock()) + with mock.patch.object(ri, + '_get_state_change_monitor_process_manager')\ + as m_get_state: + mock_pm = m_get_state.return_value + mock_pm.active = True + mock_pm.pid = 1234 + ri.spawn_state_change_monitor(mock_pm) + + mock_pm.enable.assert_called_once() + mock_log.assert_called_once() + + @mock.patch.object(ha_router.LOG, 'warning') + def test_spawn_state_change_monitor_no_pid(self, mock_log): + ri = self._create_router(mock.MagicMock()) + with mock.patch.object(ri, + '_get_state_change_monitor_process_manager')\ + as m_get_state: + mock_pm = m_get_state.return_value + mock_pm.active = True + mock_pm.pid = None + ri.spawn_state_change_monitor(mock_pm) + + mock_pm.enable.assert_called_once() + mock_log.assert_called_once() + def test_destroy_state_change_monitor_ok(self): ri = self._create_router(mock.MagicMock()) # need a port for destroy_state_change_monitor() to call PM code