Repository: dmwm/wmcore
Issue: [py2py3] Python3 issues with REST/Format module in central services

**Impact of the bug**
ReqMgr2 (and likely other WMCore web-services)

**Describe the bug**
I have spotted at least two issues with the WMCore/REST/Format module when running `reqmgr2` in a python3 stack:
1) first issue is regarding unicode encoding before hashing, see [1]
2) once that is fixed, we hit another bytes/string issue, see [2]

There could be other issues once item 2) is fixed as well.

**How to reproduce it**
Deploy `reqmgr2` in a python3 stack, using tag `1.4.9.pre8`.

**Expected behavior**
We should solve the problems reported above, and anything else that comes after those. The goal is that we can run reqmgr2 service without crashing even the most basic API calls, like the one executed by the ServerMonitor.

**Additional context and error message**
[1]
```
[10/Jun/2021:16:54:10] alancc7-cloud1.cern.ch 137.138.121.12 "GET /reqmgr2/data/request?status=staged&detail=True HTTP/1.1" 500 Internal Server Error [data: 3855 in 745 out 28116 us ] [auth: OK "/DC=ch/DC=cern/OU=computers/CN=wmagent/vocm
s0192.cern.ch" "" ] [ref: "" "WMCore.Services.Requests/v002" ]
[10/Jun/2021:16:54:10]  SERVER REST ERROR WMCore.REST.Error.ExecutionError 5aa62221a240c6e62e4a5a1f523c60f7 (Execution error)
[10/Jun/2021:16:54:10]    Traceback (most recent call last):
[10/Jun/2021:16:54:10]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Format.py", line 244, in stream_chunked
[10/Jun/2021:16:54:10]        etag.update(preamble)
[10/Jun/2021:16:54:10]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Format.py", line 438, in update
[10/Jun/2021:16:54:10]        self.digest.update(val)
[10/Jun/2021:16:54:10]    TypeError: Unicode-objects must be encoded before hashing
[10/Jun/2021:16:54:10]  SERVER HTTP ERROR cherrypy._cperror.HTTPError 4752d223e74d595fd64ea84359f49bf2 ((500, 'Execution error'))
[10/Jun/2021:16:54:10]    Traceback (most recent call last):
[10/Jun/2021:16:54:10]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Server.py", line 726, in default
[10/Jun/2021:16:54:10]        return self._call(RESTArgs(list(args), kwargs))
[10/Jun/2021:16:54:10]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Server.py", line 842, in _call
[10/Jun/2021:16:54:10]        return stream_maybe_etag(apiobj.get('etag_limit', self.etag_limit), etagger, reply)
[10/Jun/2021:16:54:10]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Format.py", line 603, in stream_maybe_etag
[10/Jun/2021:16:54:10]        raise cherrypy.HTTPError(int(err), message)
[10/Jun/2021:16:54:10]    cherrypy._cperror.HTTPError: (500, 'Execution error')
```

[2]
```
[10/Jun/2021:17:04:37] alancc7-cloud1.cern.ch 137.138.121.12 "GET /reqmgr2/data/transferinfo/ALL_DOCS HTTP/1.1" 500 Internal Server Error [data: 3831 in 742 out 127222 us ] [auth: OK "/DC=ch/DC=cern/OU=computers/CN=wmagent/vocms0192.cern.ch" "" ] [ref: "" "WMCore.Services.Requests/v002" ]
[10/Jun/2021:17:04:37]  SERVER OTHER ERROR __builtins__.TypeError 362a9a62e066780c8b3ef9367930ec43 (a bytes-like object is required, not 'str')
[10/Jun/2021:17:04:37]    Traceback (most recent call last):
[10/Jun/2021:17:04:37]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Server.py", line 726, in default
[10/Jun/2021:17:04:37]        return self._call(RESTArgs(list(args), kwargs))
[10/Jun/2021:17:04:37]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Server.py", line 842, in _call
[10/Jun/2021:17:04:37]        return stream_maybe_etag(apiobj.get('etag_limit', self.etag_limit), etagger, reply)
[10/Jun/2021:17:04:37]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Format.py", line 589, in stream_maybe_etag
[10/Jun/2021:17:04:37]        for chunk in reply:
[10/Jun/2021:17:04:37]      File "/data/srv/HG2106e-comp2/sw.amaltaro/slc7_amd64_gcc630/cms/reqmgr2/1.4.9.pre8/lib/python3.8/site-packages/WMCore/REST/Format.py", line 487, in _stream_compress_deflate
[10/Jun/2021:17:04:37]        yield z.compress("".join(pending)) + z.flush(zlib.Z_FINISH)
[10/Jun/2021:17:04:37]    TypeError: a bytes-like object is required, not 'str'
```

Changed files:
src/python/WMCore/REST/Format.py

diff --git a/src/python/WMCore/REST/Format.py b/src/python/WMCore/REST/Format.py
index c3ac76f9a..34bb99df8 100644
--- a/src/python/WMCore/REST/Format.py
+++ b/src/python/WMCore/REST/Format.py
@@ -2,12 +2,11 @@ from __future__ import print_function
 
 from builtins import str, bytes, object
 from Utils.PythonVersion import PY3
-from Utils.Utilities import encodeUnicodeToBytes
+from Utils.Utilities import encodeUnicodeToBytes, encodeUnicodeToBytesConditional
 from future.utils import viewitems
 
 import hashlib
 import json
-import types
 import xml.sax.saxutils
 import zlib
 from traceback import format_exc
@@ -616,6 +615,8 @@ def stream_maybe_etag(size_limit, etag, reply):
     res.headers['Content-Length'] = size
     # TODO investigate why `result` is a list of bytes strings in py3
     # The current solution seems to work in both py2 and py3
-    result = b"".join(result) if PY3 else "".join(result)
-    assert len(result) == size
-    return result
+    resp = b"" if PY3 else ""
+    for item in result:
+        resp += encodeUnicodeToBytesConditional(item, condition=PY3)
+    assert len(resp) == size
+    return resp