From d1efeeb433f090fabb02a07eabfa66576ebea9ea Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Tue, 19 Jun 2018 16:26:46 -0400 Subject: [PATCH] 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 --- neutron/agent/linux/utils.py | 30 +++++++++++------- neutron/tests/unit/agent/linux/test_utils.py | 32 +++++++++++++++++--- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/neutron/agent/linux/utils.py b/neutron/agent/linux/utils.py index 4eae41b62ad..90be6b5a58f 100644 --- a/neutron/agent/linux/utils.py +++ b/neutron/agent/linux/utils.py @@ -387,24 +387,32 @@ class UnixDomainHTTPConnection(httplib.HTTPConnection): class UnixDomainHttpProtocol(eventlet.wsgi.HttpProtocol): - def __init__(self, request, client_address, server): - if not client_address: - client_address = ('', 0) - + def __init__(self, *args): # NOTE(yamahata): from eventlet v0.22 HttpProtocol.__init__ # signature was changed by changeset of # 7f53465578543156e7251e243c0636e087a8445f - # try the new signature first, and then fallback to the old - # signature for compatibility - try: - conn_state = [client_address, request, eventlet.wsgi.STATE_CLOSE] + # Both have server as last arg, but first arg(s) differ + server = args[-1] + + # 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] = ('', 0) # base class is old-style, so super does not work properly eventlet.wsgi.HttpProtocol.__init__(self, conn_state, server) - except (AttributeError, TypeError): - # AttributeError: missing STATE_CLOSE - # TypeError: signature mismatch + elif len(args) == 3: + request = args[0] + client_address = args[1] + if not client_address: + client_address = ('', 0) + # base class is old-style, so super does not work properly eventlet.wsgi.HttpProtocol.__init__( self, request, client_address, server) + else: + eventlet.wsgi.HttpProtocol.__init__(self, *args) class UnixDomainWSGIServer(wsgi.Server): diff --git a/neutron/tests/unit/agent/linux/test_utils.py b/neutron/tests/unit/agent/linux/test_utils.py index 6bb2696114a..bbf96f04715 100644 --- a/neutron/tests/unit/agent/linux/test_utils.py +++ b/neutron/tests/unit/agent/linux/test_utils.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +import copy import signal import socket @@ -483,14 +484,37 @@ class TestUnixDomainHttpConnection(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): for addr in ('', b''): - u = utils.UnixDomainHttpProtocol(mock.Mock(), addr, mock.Mock()) - self.assertEqual(u.client_address, ('', 0)) + utils.UnixDomainHttpProtocol(mock.Mock(), addr, mock.Mock()) + self.ewhi.assert_called_once_with(mock.ANY, mock.ANY, + ('', 0), mock.ANY) + self.ewhi.reset_mock() def test_init_with_client(self): - u = utils.UnixDomainHttpProtocol(mock.Mock(), 'foo', mock.Mock()) - self.assertEqual(u.client_address, 'foo') + utils.UnixDomainHttpProtocol(mock.Mock(), 'foo', mock.Mock()) + 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] = ('', 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):