# response was not JSON, ignore the exception
pass
ret = (response.status, response.reason, respstr, respdata)
- except httplib.ImproperConnectionState:
+ except httplib.HTTPException:
# If we were using a cached connection, try again with a new one.
with excutils.save_and_reraise_exception() as ctxt:
- if not reconnect:
- ctxt.reraise = False
-
- if self.currentconn:
self.currentconn.close()
+ if reconnect:
+ # if reconnect is true, this was on a fresh connection so
+ # reraise since this server seems to be broken
+ ctxt.reraise = True
+ else:
+ # if reconnect is false, it was a cached connection so
+ # try one more time before re-raising
+ ctxt.reraise = False
return self.rest_call(action, resource, data, headers,
timeout=timeout, reconnect=True)
except (socket.timeout, socket.error) as e:
+ self.currentconn.close()
LOG.error(_('ServerProxy: %(action)s failure, %(e)r'),
{'action': action, 'e': e})
ret = 0, None, None, None
#
# @author: Kevin Benton, kevin.benton@bigswitch.com
#
+import httplib
+import socket
+
from contextlib import nested
import mock
from oslo.config import cfg
from neutron.plugins.bigswitch import servermanager
from neutron.tests.unit.bigswitch import test_restproxy_plugin as test_rp
+HTTPCON = 'httplib.HTTPConnection'
SERVERMANAGER = 'neutron.plugins.bigswitch.servermanager'
mock.call.read(),
mock.call.write('certdata')
])
+
+ def test_reconnect_cached_connection(self):
+ sp = servermanager.ServerPool()
+ with mock.patch(HTTPCON) as conmock:
+ rv = conmock.return_value
+ rv.getresponse.return_value.getheader.return_value = 'HASH'
+ sp.servers[0].capabilities = ['keep-alive']
+ sp.servers[0].rest_call('GET', '/first')
+ # raise an error on re-use to verify reconnect
+ # return okay the second time so the reconnect works
+ rv.request.side_effect = [httplib.ImproperConnectionState(),
+ mock.MagicMock()]
+ sp.servers[0].rest_call('GET', '/second')
+ uris = [c[1][1] for c in rv.request.mock_calls]
+ expected = [
+ sp.base_uri + '/first',
+ sp.base_uri + '/second',
+ sp.base_uri + '/second',
+ ]
+ self.assertEqual(uris, expected)
+
+ def test_no_reconnect_recurse_to_infinity(self):
+ # retry uses recursion when a reconnect is necessary
+ # this test makes sure it stops after 1 recursive call
+ sp = servermanager.ServerPool()
+ with mock.patch(HTTPCON) as conmock:
+ rv = conmock.return_value
+ # hash header must be string instead of mock object
+ rv.getresponse.return_value.getheader.return_value = 'HASH'
+ sp.servers[0].capabilities = ['keep-alive']
+ sp.servers[0].rest_call('GET', '/first')
+ # after retrying once, the rest call should raise the
+ # exception up
+ rv.request.side_effect = httplib.ImproperConnectionState()
+ self.assertRaises(httplib.ImproperConnectionState,
+ sp.servers[0].rest_call,
+ *('GET', '/second'))
+ # 1 for the first call, 2 for the second with retry
+ self.assertEqual(rv.request.call_count, 3)
+
+ def test_socket_error(self):
+ sp = servermanager.ServerPool()
+ with mock.patch(HTTPCON) as conmock:
+ conmock.return_value.request.side_effect = socket.timeout()
+ resp = sp.servers[0].rest_call('GET', '/')
+ self.assertEqual(resp, (0, None, None, None))