]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
L3 agent should do report state before full sync at start
authorStephen Ma <stephen.ma@hp.com>
Thu, 4 Jun 2015 20:09:23 +0000 (20:09 +0000)
committerStephen Ma <stephen.ma@hp.com>
Sat, 6 Jun 2015 04:46:50 +0000 (21:46 -0700)
Sometimes the AgentNotFoundByTypeHost exception is reported during
L3-agent startup. The exception is generated when the first
get_routers RPC call is made. When the neutron server gets this
RPC call, it might not have handled the report state RPC call yet.
So the L3-agent hasn't been registered in the API server.
The result is a RPC Error exception.  By the time the next
get_routers RPC call is made, the report state RPC call has already
been done and agent registered.

This patch modifies the L3 agent startup behavior to have the report
state done before the agent do the sync routers RPC call.

Closes-bug: 1456822
Change-Id: Id40cfd8466f45e20fea0e9df6fd57bf9c9e59da7

neutron/agent/l3/agent.py
neutron/tests/unit/agent/l3/test_agent.py

index 01395d34ccfadea8803ba6dbf8700577f8902a43..680401979ce54731f918f7f4845a02faabe2dacd 100644 (file)
@@ -546,6 +546,11 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
                 self._queue.add(update)
 
     def after_start(self):
+        # Note: the FWaaS' vArmourL3NATAgent is a subclass of L3NATAgent. It
+        # calls this method here. So Removing this after_start() would break
+        # vArmourL3NATAgent. We need to find out whether vArmourL3NATAgent
+        # can have L3NATAgentWithStateReport as its base class instead of
+        # L3NATAgent.
         eventlet.spawn_n(self._process_routers_loop)
         LOG.info(_LI("L3 agent started"))
         # When L3 agent is ready, we immediately do a full sync
@@ -555,6 +560,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
 class L3NATAgentWithStateReport(L3NATAgent):
 
     def __init__(self, host, conf=None):
+        self.use_call = True
         super(L3NATAgentWithStateReport, self).__init__(host=host, conf=conf)
         self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN)
         self.agent_state = {
@@ -574,7 +580,6 @@ class L3NATAgentWithStateReport(L3NATAgent):
             'start_flag': True,
             'agent_type': l3_constants.AGENT_TYPE_L3}
         report_interval = self.conf.AGENT.report_interval
-        self.use_call = True
         if report_interval:
             self.heartbeat = loopingcall.FixedIntervalLoopingCall(
                 self._report_state)
@@ -613,6 +618,15 @@ class L3NATAgentWithStateReport(L3NATAgent):
         except Exception:
             LOG.exception(_LE("Failed reporting state!"))
 
+    def after_start(self):
+        eventlet.spawn_n(self._process_routers_loop)
+        LOG.info(_LI("L3 agent started"))
+        # Do the report state before we do the first full sync.
+        self._report_state()
+
+        # When L3 agent is ready, we immediately do a full sync
+        self.periodic_sync_routers_task(self.context)
+
     def agent_updated(self, context, payload):
         """Handle the agent_updated notification event."""
         self.fullsync = True
index e628cd465c7e3e2c347bf51b262d85fd32165a52..627088f3d571bb54f2803ab76eb6456cf7c7e20c 100644 (file)
@@ -39,6 +39,7 @@ from neutron.agent.linux import external_process
 from neutron.agent.linux import interface
 from neutron.agent.linux import ra
 from neutron.agent.metadata import driver as metadata_driver
+from neutron.agent import rpc as agent_rpc
 from neutron.callbacks import manager
 from neutron.callbacks import registry
 from neutron.common import config as base_config
@@ -283,6 +284,7 @@ class BasicRouterOperationsFramework(base.BaseTestCase):
         self.conf = agent_config.setup_conf()
         self.conf.register_opts(base_config.core_opts)
         log.register_options(self.conf)
+        self.conf.register_opts(agent_config.AGENT_STATE_OPTS, 'AGENT')
         self.conf.register_opts(l3_config.OPTS)
         self.conf.register_opts(ha.OPTS)
         agent_config.register_interface_driver_opts_helper(self.conf)
@@ -420,6 +422,24 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
                 agent.after_start()
                 router_sync.assert_called_once_with(agent.context)
 
+    def test_l3_initial_report_state_done(self):
+        with mock.patch.object(l3_agent.L3NATAgentWithStateReport,
+                               'periodic_sync_routers_task'),\
+                mock.patch.object(agent_rpc.PluginReportStateAPI,
+                                  'report_state') as report_state,\
+                mock.patch.object(eventlet, 'spawn_n'):
+
+            agent = l3_agent.L3NATAgentWithStateReport(host=HOSTNAME,
+                                                       conf=self.conf)
+
+            self.assertEqual(agent.agent_state['start_flag'], True)
+            use_call_arg = agent.use_call
+            agent.after_start()
+            report_state.assert_called_once_with(agent.context,
+                                                 agent.agent_state,
+                                                 use_call_arg)
+            self.assertTrue(agent.agent_state.get('start_flag') is None)
+
     def test_periodic_sync_routers_task_call_clean_stale_namespaces(self):
         agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
         self.plugin_api.get_routers.return_value = []