From 4927b1f29c4d993cb29786312a9efc00850c10cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20L=C3=A9cuyer?= Date: Thu, 16 May 2019 18:08:03 +0200 Subject: [PATCH] Specify pickle protocol in REPLICATE() The default pickle protocol in python3 is version 3. This is not readable by a python2 interpreter. Force the use of version 2 in the object server REPLICATE() function, for compatibility with python 2. Change-Id: I19d23570ff3a084d288de1308e059cfd8134d6ad --- swift/obj/server.py | 3 ++- test/unit/obj/test_server.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/swift/obj/server.py b/swift/obj/server.py index 0519bcb53e..b1e34a5d7e 100644 --- a/swift/obj/server.py +++ b/swift/obj/server.py @@ -1256,7 +1256,8 @@ class ObjectController(BaseStorageServer): except DiskFileDeviceUnavailable: resp = HTTPInsufficientStorage(drive=device, request=request) else: - resp = Response(body=pickle.dumps(hashes)) + # force pickle protocol for compatibility with py2 nodes + resp = Response(body=pickle.dumps(hashes, protocol=2)) return resp @public diff --git a/test/unit/obj/test_server.py b/test/unit/obj/test_server.py index 2ff6a0a8e9..23ae40700e 100644 --- a/test/unit/obj/test_server.py +++ b/test/unit/obj/test_server.py @@ -6812,6 +6812,34 @@ class TestObjectController(unittest.TestCase): tpool.execute = was_tpool_exe diskfile.DiskFileManager._get_hashes = was_get_hashes + def test_REPLICATE_pickle_protocol(self): + + def fake_get_hashes(*args, **kwargs): + return 0, {1: 2} + + def my_tpool_execute(func, *args, **kwargs): + return func(*args, **kwargs) + + was_get_hashes = diskfile.DiskFileManager._get_hashes + was_tpool_exe = tpool.execute + try: + diskfile.DiskFileManager._get_hashes = fake_get_hashes + tpool.execute = my_tpool_execute + req = Request.blank('/sda1/p/suff', + environ={'REQUEST_METHOD': 'REPLICATE'}, + headers={}) + with mock.patch('swift.obj.server.pickle.dumps') as fake_pickle: + fake_pickle.return_value = b'' + req.get_response(self.object_controller) + # This is the key assertion: starting in Python 3.0, the + # default protocol version is 3, but such pickles can't be read + # on Python 2. As long as we may need to talk to a Python 2 + # process, we need to cap our protocol version. + fake_pickle.assert_called_once_with({1: 2}, protocol=2) + finally: + tpool.execute = was_tpool_exe + diskfile.DiskFileManager._get_hashes = was_get_hashes + def test_REPLICATE_timeout(self): def fake_get_hashes(*args, **kwargs):