Undo the eventlet monkey patch for the privileged daemon
Backport Notes: - We want to avoid requirements bump on stable branch so we don't backport requirements and lower-constraints changes. - Tests are skipped because SSL on Python2 with monkey patch work differently than with Python3 (tests are uncompatible). Change-Id: I422125b137a3beadb0a79f5944a19fce62f093d6 Closes-Bug: #1887506 (cherry picked from commit1dc378c76f
) (cherry picked from commit6d41ef9f91
)
This commit is contained in:
parent
6db45ef76d
commit
00e69d4f32
|
@ -57,6 +57,7 @@ import tempfile
|
|||
import threading
|
||||
|
||||
import eventlet
|
||||
from eventlet import patcher
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import encodeutils
|
||||
|
@ -75,6 +76,25 @@ if platform.system() == 'Linux':
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
EVENTLET_MODULES = ('os', 'select', 'socket', 'thread', 'time', 'MySQLdb',
|
||||
'builtins', 'subprocess')
|
||||
EVENTLET_LIBRARIES = []
|
||||
|
||||
|
||||
def _null():
|
||||
return []
|
||||
|
||||
|
||||
for module in EVENTLET_MODULES:
|
||||
if hasattr(patcher, '_green_%s_modules' % module):
|
||||
method = getattr(patcher, '_green_%s_modules' % module)
|
||||
elif hasattr(patcher, '_green_%s' % module):
|
||||
method = getattr(patcher, '_green_%s' % module)
|
||||
else:
|
||||
method = _null()
|
||||
EVENTLET_LIBRARIES.append((module, method))
|
||||
|
||||
|
||||
@enum.unique
|
||||
class StdioFd(enum.IntEnum):
|
||||
# NOTE(gus): We can't use sys.std*.fileno() here. sys.std*
|
||||
|
@ -258,6 +278,21 @@ def replace_logging(handler, log_root=None):
|
|||
log_root.addHandler(handler)
|
||||
|
||||
|
||||
def un_monkey_patch():
|
||||
for eventlet_mod_name, func_modules in EVENTLET_LIBRARIES:
|
||||
if not eventlet.patcher.is_monkey_patched(eventlet_mod_name):
|
||||
continue
|
||||
|
||||
for name, mod in func_modules():
|
||||
patched_mod = sys.modules.get(name)
|
||||
orig_mod = eventlet.patcher.original(name)
|
||||
for attr_name in mod.__patched__:
|
||||
patched_attr = getattr(mod, attr_name, None)
|
||||
unpatched_attr = getattr(orig_mod, attr_name, None)
|
||||
if patched_attr is not None:
|
||||
setattr(patched_mod, attr_name, unpatched_attr)
|
||||
|
||||
|
||||
class ForkingClientChannel(_ClientChannel):
|
||||
def __init__(self, context):
|
||||
"""Start privsep daemon using fork()
|
||||
|
@ -279,6 +314,7 @@ class ForkingClientChannel(_ClientChannel):
|
|||
|
||||
if os.fork() == 0:
|
||||
# child
|
||||
un_monkey_patch()
|
||||
|
||||
channel = comm.ServerChannel(sock_b)
|
||||
sock_a.close()
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
# under the License.
|
||||
|
||||
import copy
|
||||
import eventlet
|
||||
import fixtures
|
||||
import functools
|
||||
import logging as pylogging
|
||||
import mock
|
||||
import platform
|
||||
import sys
|
||||
import time
|
||||
|
||||
from oslo_log import formatters
|
||||
|
@ -212,3 +214,31 @@ class ClientChannelTestCase(base.BaseTestCase):
|
|||
with mock.patch.object(daemon.LOG, 'warning') as mock_warning:
|
||||
self.client_channel.out_of_band([daemon.Message.PING])
|
||||
mock_warning.assert_called_once()
|
||||
|
||||
|
||||
class UnMonkeyPatch(base.BaseTestCase):
|
||||
|
||||
@testtools.skipIf(sys.version_info < (3, 0), 'works only with python 3')
|
||||
def test_un_monkey_patch(self):
|
||||
self.assertFalse(any(
|
||||
eventlet.patcher.is_monkey_patched(eventlet_mod_name)
|
||||
for eventlet_mod_name in daemon.EVENTLET_MODULES))
|
||||
|
||||
eventlet.monkey_patch()
|
||||
self.assertTrue(any(
|
||||
eventlet.patcher.is_monkey_patched(eventlet_mod_name)
|
||||
for eventlet_mod_name in daemon.EVENTLET_MODULES))
|
||||
|
||||
daemon.un_monkey_patch()
|
||||
for eventlet_mod_name, func_modules in daemon.EVENTLET_LIBRARIES:
|
||||
if not eventlet.patcher.is_monkey_patched(eventlet_mod_name):
|
||||
continue
|
||||
|
||||
for name, green_mod in func_modules():
|
||||
orig_mod = eventlet.patcher.original(name)
|
||||
patched_mod = sys.modules.get(name)
|
||||
for attr_name in green_mod.__patched__:
|
||||
un_monkey_patched_attr = getattr(patched_mod, attr_name,
|
||||
None)
|
||||
original_attr = getattr(orig_mod, attr_name, None)
|
||||
self.assertEqual(un_monkey_patched_attr, original_attr)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
other:
|
||||
- |
|
||||
The ``oslo.privsep`` client can be called from a program using eventlet.
|
||||
If ``eventlet.monkey_patch``, some libraries will be patched, for example
|
||||
``threading`` or ``os``. When the root daemon is forked from the client
|
||||
process, those libraries remain patched. Now, when the daemon is forked
|
||||
from the client process, those libraries and methods are restored to the
|
||||
original values. The goal is to prevent some timeouts when using eventlet
|
||||
threads (user threads); system threads are preemptive and the code does
|
||||
not need to care about the executor token.
|
Loading…
Reference in New Issue