diff --git a/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini b/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini index 9c8e6b58894..45aa9451701 100644 --- a/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini +++ b/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini @@ -149,6 +149,11 @@ # # enable_distributed_routing = False +# (IntOpt) Set new timeout in seconds for new rpc calls after agent receives +# SIGTERM. If value is set to 0, rpc timeout won't be changed" +# +# quitting_rpc_timeout = 10 + [securitygroup] # Firewall driver for realizing neutron security group function. # firewall_driver = neutron.agent.firewall.NoopFirewallDriver diff --git a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py index 68325a3ca5b..eb5efd5b1be 100644 --- a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py @@ -140,7 +140,8 @@ class OVSNeutronAgent(n_rpc.RpcCallback, ovsdb_monitor_respawn_interval=( constants.DEFAULT_OVSDBMON_RESPAWN), arp_responder=False, - use_veth_interconnection=False): + use_veth_interconnection=False, + quitting_rpc_timeout=None): '''Constructor. :param integ_br: name of the integration bridge. @@ -163,6 +164,8 @@ class OVSNeutronAgent(n_rpc.RpcCallback, supported. :param use_veth_interconnection: use veths instead of patch ports to interconnect the integration bridge to physical bridges. + :param quitting_rpc_timeout: timeout in seconds for rpc calls after + SIGTERM is received ''' super(OVSNeutronAgent, self).__init__() self.use_veth_interconnection = use_veth_interconnection @@ -253,6 +256,8 @@ class OVSNeutronAgent(n_rpc.RpcCallback, # The initialization is complete; we can start receiving messages self.connection.consume_in_threads() + self.quitting_rpc_timeout = quitting_rpc_timeout + def _report_state(self): # How many devices are likely used by a VM self.agent_state.get('configurations')['devices'] = ( @@ -1479,6 +1484,12 @@ class OVSNeutronAgent(n_rpc.RpcCallback, def _handle_sigterm(self, signum, frame): LOG.debug("Agent caught SIGTERM, quitting daemon loop.") self.run_daemon_loop = False + if self.quitting_rpc_timeout: + self.set_rpc_timeout(self.quitting_rpc_timeout) + + def set_rpc_timeout(self, timeout): + for rpc_api in (self.plugin_rpc, self.state_rpc): + rpc_api._client.timeout = timeout def create_agent_config_map(config): @@ -1506,6 +1517,7 @@ def create_agent_config_map(config): l2_population=config.AGENT.l2_population, arp_responder=config.AGENT.arp_responder, use_veth_interconnection=config.OVS.use_veth_interconnection, + quitting_rpc_timeout=config.AGENT.quitting_rpc_timeout ) # If enable_tunneling is TRUE, set tunnel_type to default to GRE diff --git a/neutron/plugins/openvswitch/common/config.py b/neutron/plugins/openvswitch/common/config.py index d9e0454839c..f3bb1e19100 100644 --- a/neutron/plugins/openvswitch/common/config.py +++ b/neutron/plugins/openvswitch/common/config.py @@ -94,6 +94,10 @@ agent_opts = [ "outgoing IP packet carrying GRE/VXLAN tunnel.")), cfg.BoolOpt('enable_distributed_routing', default=False, help=_("Make the l2 agent run in DVR mode.")), + cfg.IntOpt('quitting_rpc_timeout', default=10, + help=_("Set new timeout in seconds for new rpc calls after " + "agent receives SIGTERM. If value is set to 0, rpc " + "timeout won't be changed")) ] diff --git a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py index 64ba72a9058..b2fafb9efd3 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py @@ -104,6 +104,7 @@ class TestOvsNeutronAgent(base.BaseTestCase): cfg.CONF.set_default('firewall_driver', 'neutron.agent.firewall.NoopFirewallDriver', group='SECURITYGROUP') + cfg.CONF.set_default('quitting_rpc_timeout', 10, 'AGENT') kwargs = ovs_neutron_agent.create_agent_config_map(cfg.CONF) class MockFixedIntervalLoopingCall(object): @@ -1403,6 +1404,18 @@ class TestOvsNeutronAgent(base.BaseTestCase): setup_int_br.assert_has_calls([mock.call()]) setup_phys_br.assert_has_calls([mock.call({})]) + def test_set_rpc_timeout(self): + self.agent._handle_sigterm(None, None) + for rpc_client in (self.agent.plugin_rpc._client, + self.agent.state_rpc._client): + self.assertEqual(10, rpc_client.timeout) + + def test_set_rpc_timeout_no_value(self): + self.agent.quitting_rpc_timeout = None + with mock.patch.object(self.agent, 'set_rpc_timeout') as mock_set_rpc: + self.agent._handle_sigterm(None, None) + self.assertFalse(mock_set_rpc.called) + class AncillaryBridgesTest(base.BaseTestCase):