Fix UnixDomainHttpProtocol class to support all eventlet versions

It was recently decided to uncap eventlet:
http://lists.openstack.org/pipermail/openstack-dev/2018-April/129096.html
So eventlet is now capped at 0.20 not by global requirements,
it is capped in upper-constraints, because currently not every
openstack project is able to work with a newer eventlet version,
mostly because of the caps in projects requirements.txt.
According to global-requirements, last allowed version of
eventlet is 0.22.1:
https://git.openstack.org/cgit/openstack/requirements/tree/global-requirements.txt

In an effort to support both eventlet<0.22 and eventlet>=0.22,
change the code to try and determine the correct number of
arguments to use in the call to initialize the parent class.

Change-Id: Ibe3dc8af6cf9f8bb4f8eababb7f4276e4db3f1f9
Closes-bug: #1777640
This commit is contained in:
Brian Haley 2018-06-19 16:26:46 -04:00
parent abbd534fdf
commit d1efeeb433
2 changed files with 47 additions and 15 deletions

View File

@ -387,24 +387,32 @@ class UnixDomainHTTPConnection(httplib.HTTPConnection):
class UnixDomainHttpProtocol(eventlet.wsgi.HttpProtocol): class UnixDomainHttpProtocol(eventlet.wsgi.HttpProtocol):
def __init__(self, request, client_address, server): def __init__(self, *args):
if not client_address:
client_address = ('<local>', 0)
# NOTE(yamahata): from eventlet v0.22 HttpProtocol.__init__ # NOTE(yamahata): from eventlet v0.22 HttpProtocol.__init__
# signature was changed by changeset of # signature was changed by changeset of
# 7f53465578543156e7251e243c0636e087a8445f # 7f53465578543156e7251e243c0636e087a8445f
# try the new signature first, and then fallback to the old # Both have server as last arg, but first arg(s) differ
# signature for compatibility server = args[-1]
try:
conn_state = [client_address, request, eventlet.wsgi.STATE_CLOSE] # Because the caller is eventlet.wsgi.Server.process_request,
# the number of arguments will dictate if it is new or old style.
if len(args) == 2:
conn_state = args[0]
client_address = conn_state[0]
if not client_address:
conn_state[0] = ('<local>', 0)
# base class is old-style, so super does not work properly # base class is old-style, so super does not work properly
eventlet.wsgi.HttpProtocol.__init__(self, conn_state, server) eventlet.wsgi.HttpProtocol.__init__(self, conn_state, server)
except (AttributeError, TypeError): elif len(args) == 3:
# AttributeError: missing STATE_CLOSE request = args[0]
# TypeError: signature mismatch client_address = args[1]
if not client_address:
client_address = ('<local>', 0)
# base class is old-style, so super does not work properly
eventlet.wsgi.HttpProtocol.__init__( eventlet.wsgi.HttpProtocol.__init__(
self, request, client_address, server) self, request, client_address, server)
else:
eventlet.wsgi.HttpProtocol.__init__(self, *args)
class UnixDomainWSGIServer(wsgi.Server): class UnixDomainWSGIServer(wsgi.Server):

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import copy
import signal import signal
import socket import socket
@ -483,14 +484,37 @@ class TestUnixDomainHttpConnection(base.BaseTestCase):
class TestUnixDomainHttpProtocol(base.BaseTestCase): class TestUnixDomainHttpProtocol(base.BaseTestCase):
def setUp(self):
super(TestUnixDomainHttpProtocol, self).setUp()
self.ewhi = mock.patch('eventlet.wsgi.HttpProtocol.__init__').start()
def test_init_empty_client(self): def test_init_empty_client(self):
for addr in ('', b''): for addr in ('', b''):
u = utils.UnixDomainHttpProtocol(mock.Mock(), addr, mock.Mock()) utils.UnixDomainHttpProtocol(mock.Mock(), addr, mock.Mock())
self.assertEqual(u.client_address, ('<local>', 0)) self.ewhi.assert_called_once_with(mock.ANY, mock.ANY,
('<local>', 0), mock.ANY)
self.ewhi.reset_mock()
def test_init_with_client(self): def test_init_with_client(self):
u = utils.UnixDomainHttpProtocol(mock.Mock(), 'foo', mock.Mock()) utils.UnixDomainHttpProtocol(mock.Mock(), 'foo', mock.Mock())
self.assertEqual(u.client_address, 'foo') self.ewhi.assert_called_once_with(mock.ANY, mock.ANY, 'foo', mock.ANY)
def test_init_new_style_empty_client(self):
conn_state = ['', mock.Mock(), mock.Mock()]
# have to make a copy since the init will modify what we pass
csc = copy.copy(conn_state)
csc[0] = ('<local>', 0)
utils.UnixDomainHttpProtocol(conn_state, mock.Mock())
self.ewhi.assert_called_once_with(mock.ANY, csc, mock.ANY)
def test_init_new_style_client(self):
conn_state = ['foo', mock.Mock(), mock.Mock()]
utils.UnixDomainHttpProtocol(conn_state, mock.Mock())
self.ewhi.assert_called_once_with(mock.ANY, conn_state, mock.ANY)
def test_init_unknown_client(self):
utils.UnixDomainHttpProtocol('foo')
self.ewhi.assert_called_once_with(mock.ANY, 'foo')
class TestUnixDomainWSGIServer(base.BaseTestCase): class TestUnixDomainWSGIServer(base.BaseTestCase):