File 0009-Fix-l3-agent-crash-on-routers-without-ha-state.patch of Package openstack-neutron

Index: neutron-9.4.2.dev21/neutron/agent/l3/agent.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/agent/l3/agent.py
+++ neutron-9.4.2.dev21/neutron/agent/l3/agent.py
@@ -473,13 +473,14 @@ class L3NATAgent(ha.AgentMixin,
         self.l3_ext_manager.add_router(self.context, router)
 
     def _process_updated_router(self, router):
+        ri = self.router_info[router['id']]
         is_dvr_only_agent = (
             self.conf.agent_mode == lib_const.L3_AGENT_MODE_DVR)
+        is_ha_router = getattr(ri, 'ha_state', None) is not None
         # For HA routers check that DB state matches actual state
-        if router.get('ha') and not is_dvr_only_agent:
+        if router.get('ha') and not is_dvr_only_agent and is_ha_router:
             self.check_ha_state_for_router(
                 router['id'], router.get(l3_constants.HA_ROUTER_STATE_KEY))
-        ri = self.router_info[router['id']]
         ri.router = router
         registry.notify(resources.ROUTER, events.BEFORE_UPDATE,
                         self, router=ri)
Index: neutron-9.4.2.dev21/neutron/tests/functional/agent/l3/test_dvr_router.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/tests/functional/agent/l3/test_dvr_router.py
+++ neutron-9.4.2.dev21/neutron/tests/functional/agent/l3/test_dvr_router.py
@@ -958,8 +958,8 @@ class TestDvrRouter(framework.L3AgentTes
         self.assertFalse(sg_device)
         self.assertTrue(qg_device)
 
-    def _mocked_dvr_ha_router(self, agent, enable_gw=True):
-        r_info = self.generate_dvr_router_info(enable_ha=True,
+    def _mocked_dvr_ha_router(self, agent, enable_ha=True, enable_gw=True):
+        r_info = self.generate_dvr_router_info(enable_ha=enable_ha,
                                                enable_snat=True,
                                                agent=agent,
                                                enable_gw=enable_gw)
@@ -991,14 +991,19 @@ class TestDvrRouter(framework.L3AgentTes
         br_int_1.add_port(veth1.name)
         br_int_2.add_port(veth2.name)
 
-    def _create_dvr_ha_router(self, agent, enable_gw=True):
+    def _create_dvr_ha_router(self, agent, enable_gw=True, ha_interface=True):
         get_ns_name = mock.patch.object(namespaces.RouterNamespace,
                                         '_get_ns_name').start()
         get_snat_ns_name = mock.patch.object(dvr_snat_ns.SnatNamespace,
                                              'get_snat_ns_name').start()
         (r_info,
          mocked_r_ns_name,
-         mocked_r_snat_ns_name) = self._mocked_dvr_ha_router(agent, enable_gw)
+         mocked_r_snat_ns_name) = self._mocked_dvr_ha_router(
+             agent, ha_interface, enable_gw)
+
+        if not ha_interface:
+            r_info['ha'] = True
+
         get_ns_name.return_value = mocked_r_ns_name
         get_snat_ns_name.return_value = mocked_r_snat_ns_name
         router = self.manage_router(agent, r_info)
@@ -1076,6 +1081,26 @@ class TestDvrRouter(framework.L3AgentTes
     def test_dvr_ha_router_failover_without_gw(self):
         self._test_dvr_ha_router_failover(enable_gw=False)
 
+    def test_dvr_non_ha_router_update(self):
+        self._setup_dvr_ha_agents()
+        self._setup_dvr_ha_bridges()
+
+        router1 = self._create_dvr_ha_router(self.agent)
+        router2 = self._create_dvr_ha_router(self.failover_agent,
+                                             ha_interface=False)
+
+        r1_chsfr = mock.patch.object(self.agent,
+                                     'check_ha_state_for_router').start()
+        r2_chsfr = mock.patch.object(self.failover_agent,
+                                     'check_ha_state_for_router').start()
+
+        utils.wait_until_true(lambda: router1.ha_state == 'master')
+
+        self.agent._process_updated_router(router1.router)
+        self.assertTrue(r1_chsfr.called)
+        self.failover_agent._process_updated_router(router2.router)
+        self.assertFalse(r2_chsfr.called)
+
     def _setup_dvr_router_static_routes(
         self, router_namespace=True, check_fpr_int_rule_delete=False):
         """Test to validate the extra routes on dvr routers."""
Index: neutron-9.4.2.dev21/neutron/tests/unit/agent/l3/test_agent.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/tests/unit/agent/l3/test_agent.py
+++ neutron-9.4.2.dev21/neutron/tests/unit/agent/l3/test_agent.py
@@ -2249,9 +2249,10 @@ class TestBasicRouterOperations(BasicRou
                   'distributed': True, 'ha': True,
                   'external_gateway_info': {}, 'routes': [],
                   'admin_state_up': True}
-
-        agent._process_router_if_compatible(router)
-        self.assertIn(router['id'], agent.router_info)
+        with mock.patch.object(agent, 'check_ha_state_for_router') as chsfr:
+            agent._process_router_if_compatible(router)
+            self.assertIn(router['id'], agent.router_info)
+            self.assertFalse(chsfr.called)
 
     def test_process_router_if_compatible_with_no_ext_net_in_conf(self):
         self.conf.set_override('external_network_bridge', 'br-ex')
openSUSE Build Service is sponsored by