NSX-v3 http read timeout

This patch exposes a new config property named
http_read_timeout in the nsx_v3 group of nsx.ini
which allows users to configure a HTTP read timeout
separately from http connect timeout (set via http_timeout).
With this addition users can provide finer grained timeout
settings for their deployed env.

A unit test is also included.

backport: liberty

Change-Id: I6bcb142329e348c7b2224daf32bd3f648ff2af77
Closes-Bug: #1540462
This commit is contained in:
Boden R 2016-02-01 12:31:33 -07:00
parent cebfb2b5ef
commit 1e1df3bdcb
6 changed files with 39 additions and 9 deletions

View File

@ -355,9 +355,12 @@
# default system root CAs will be used. # default system root CAs will be used.
# insecure = True # insecure = True
# The time in seconds before aborting an HTTP request to a NSX manager. # The time in seconds before aborting a HTTP connection to a NSX manager.
# http_timeout = 75 # http_timeout = 75
# The time in seconds before aborting a HTTP read response from a NSX manager.
# http_read_timeout = 180
# Maxiumum number of connection connections to each NSX manager. # Maxiumum number of connection connections to each NSX manager.
# concurrent_connections = 10 # concurrent_connections = 10

View File

@ -218,8 +218,12 @@ nsx_v3_opts = [
'system root CAs will be used.')), 'system root CAs will be used.')),
cfg.IntOpt('http_timeout', cfg.IntOpt('http_timeout',
default=75, default=75,
help=_('Time before aborting a HTTP request to a ' help=_('Time before aborting a HTTP connection to a '
'NSX manager.')), 'NSX manager.')),
cfg.IntOpt('http_read_timeout',
default=180,
help=_('The time in seconds before aborting a HTTP read '
'response from a NSX manager.')),
cfg.IntOpt('concurrent_connections', default=10, cfg.IntOpt('concurrent_connections', default=10,
help=_("Maximum concurrent connections to each NSX " help=_("Maximum concurrent connections to each NSX "
"manager.")), "manager.")),

View File

@ -77,15 +77,16 @@ class TimeoutSession(requests.Session):
at the session level. at the session level.
""" """
def __init__(self, timeout=cfg.CONF.nsx_v3.http_timeout): def __init__(self, timeout=None, read_timeout=None):
self.timeout = timeout self.timeout = timeout or cfg.CONF.nsx_v3.http_timeout
self.read_timeout = read_timeout or cfg.CONF.nsx_v3.http_read_timeout
super(TimeoutSession, self).__init__() super(TimeoutSession, self).__init__()
# wrapper timeouts at the session level # wrapper timeouts at the session level
# see: https://goo.gl/xNk7aM # see: https://goo.gl/xNk7aM
def request(self, *args, **kwargs): def request(self, *args, **kwargs):
if 'timeout' not in kwargs: if 'timeout' not in kwargs:
kwargs['timeout'] = self.timeout kwargs['timeout'] = (self.timeout, self.read_timeout)
return super(TimeoutSession, self).request(*args, **kwargs) return super(TimeoutSession, self).request(*args, **kwargs)
@ -109,7 +110,8 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider):
manager=endpoint.provider.url, operation=msg) manager=endpoint.provider.url, operation=msg)
def new_connection(self, cluster_api, provider): def new_connection(self, cluster_api, provider):
session = TimeoutSession(cluster_api.http_timeout) session = TimeoutSession(cluster_api.http_timeout,
cluster_api.http_read_timeout)
session.auth = (cluster_api.username, cluster_api.password) session.auth = (cluster_api.username, cluster_api.password)
# NSX v3 doesn't use redirects # NSX v3 doesn't use redirects
session.max_redirects = 0 session.max_redirects = 0
@ -430,6 +432,7 @@ class NSXClusteredAPI(ClusteredAPI):
ca_file=None, ca_file=None,
concurrent_connections=None, concurrent_connections=None,
http_timeout=None, http_timeout=None,
http_read_timeout=None,
conn_idle_timeout=None, conn_idle_timeout=None,
http_provider=None): http_provider=None):
self.username = username or cfg.CONF.nsx_v3.nsx_api_user self.username = username or cfg.CONF.nsx_v3.nsx_api_user
@ -440,6 +443,8 @@ class NSXClusteredAPI(ClusteredAPI):
self.conns_per_pool = (concurrent_connections or self.conns_per_pool = (concurrent_connections or
cfg.CONF.nsx_v3.concurrent_connections) cfg.CONF.nsx_v3.concurrent_connections)
self.http_timeout = http_timeout or cfg.CONF.nsx_v3.http_timeout self.http_timeout = http_timeout or cfg.CONF.nsx_v3.http_timeout
self.http_read_timeout = (http_read_timeout or
cfg.CONF.nsx_v3.http_read_timeout)
self.conn_idle_timeout = (conn_idle_timeout or self.conn_idle_timeout = (conn_idle_timeout or
cfg.CONF.nsx_v3.conn_idle_timeout) cfg.CONF.nsx_v3.conn_idle_timeout)

View File

@ -27,6 +27,8 @@ NSX_PASSWORD = 'default'
NSX_MANAGER = '1.2.3.4' NSX_MANAGER = '1.2.3.4'
NSX_INSECURE = False NSX_INSECURE = False
NSX_CERT = '/opt/stack/certs/nsx.pem' NSX_CERT = '/opt/stack/certs/nsx.pem'
NSX_HTTP_TIMEOUT = 10
NSX_HTTP_READ_TIMEOUT = 180
V3_CLIENT_PKG = 'vmware_nsx.nsxlib.v3.client' V3_CLIENT_PKG = 'vmware_nsx.nsxlib.v3.client'
BRIDGE_FNS = ['create_resource', 'delete_resource', BRIDGE_FNS = ['create_resource', 'delete_resource',
@ -44,6 +46,9 @@ class NsxLibTestCase(unittest.TestCase):
cfg.CONF.set_override('nsx_api_managers', [NSX_MANAGER], 'nsx_v3') cfg.CONF.set_override('nsx_api_managers', [NSX_MANAGER], 'nsx_v3')
cfg.CONF.set_override('insecure', NSX_INSECURE, 'nsx_v3') cfg.CONF.set_override('insecure', NSX_INSECURE, 'nsx_v3')
cfg.CONF.set_override('ca_file', NSX_CERT, 'nsx_v3') cfg.CONF.set_override('ca_file', NSX_CERT, 'nsx_v3')
cfg.CONF.set_override('http_timeout', NSX_HTTP_TIMEOUT, 'nsx_v3')
cfg.CONF.set_override('http_read_timeout',
NSX_HTTP_READ_TIMEOUT, 'nsx_v3')
cfg.CONF.set_override('network_scheduler_driver', cfg.CONF.set_override('network_scheduler_driver',
'neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler') 'neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler')
@ -112,7 +117,6 @@ class NsxClientTestCase(NsxLibTestCase):
checked_kwargs = copy.copy(kwargs) checked_kwargs = copy.copy(kwargs)
del checked_kwargs['proxies'] del checked_kwargs['proxies']
del checked_kwargs['stream'] del checked_kwargs['stream']
del checked_kwargs['timeout']
if 'allow_redirects' in checked_kwargs: if 'allow_redirects' in checked_kwargs:
del checked_kwargs['allow_redirects'] del checked_kwargs['allow_redirects']

View File

@ -41,7 +41,9 @@ def _headers(**kwargs):
def assert_call(verb, client_or_resource, def assert_call(verb, client_or_resource,
url, verify=nsxlib_testcase.NSX_CERT, url, verify=nsxlib_testcase.NSX_CERT,
data=None, headers=DFT_ACCEPT_HEADERS): data=None, headers=DFT_ACCEPT_HEADERS,
timeout=(nsxlib_testcase.NSX_HTTP_TIMEOUT,
nsxlib_testcase.NSX_HTTP_READ_TIMEOUT)):
nsx_client = client_or_resource nsx_client = client_or_resource
if getattr(nsx_client, '_client', None) is not None: if getattr(nsx_client, '_client', None) is not None:
nsx_client = nsx_client._client nsx_client = nsx_client._client
@ -49,7 +51,7 @@ def assert_call(verb, client_or_resource,
cluster.assert_called_once( cluster.assert_called_once(
verb, verb,
**{'url': url, 'verify': verify, 'body': data, **{'url': url, 'verify': verify, 'body': data,
'headers': headers, 'cert': None}) 'headers': headers, 'cert': None, 'timeout': timeout})
def assert_json_call(verb, client_or_resource, url, def assert_json_call(verb, client_or_resource, url,

View File

@ -127,6 +127,18 @@ class NsxV3ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase):
for ep_id, ep in api.endpoints.items(): for ep_id, ep in api.endpoints.items():
self.assertEqual(ep.pool.max_size, 11) self.assertEqual(ep.pool.max_size, 11)
def test_timeouts(self):
cfg.CONF.set_override(
'http_read_timeout', 37, 'nsx_v3')
cfg.CONF.set_override(
'http_timeout', 7, 'nsx_v3')
api = self.mock_nsx_clustered_api()
api.get('logical-ports')
mock_call = api.recorded_calls.method_calls[0]
name, args, kwargs = mock_call
self.assertEqual(kwargs['timeout'], (7, 37))
class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase): class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase):