Repository: StackStorm/st2

Issue:
Pinned eventlet version has outstanding bugs
pinned version 0.17 of eventlet has outstanding bugs on it's monkey patching of the ssl module.

e.g.
https://github.com/eventlet/eventlet/issues/371

```
# Note: 0.20.0 removed select.poll() on which some of our code and libraries we
# depend on rely
```

@Kami  committed this reversion in https://github.com/StackStorm/st2/commit/1ec43d294e6770e56ec8f9990c805cb9dffe98c5

What was the specific issue?


Discussion:
@tonybaloney this comment seems to be the relevant one (at the time anyway) https://github.com/StackStorm/st2/pull/3538#issuecomment-312282785
Hey guys, eventlet here.

I just want to make things clear. Hopefully help, though I couldn't find any `import select` in st2 code to submit a patch.

Eventlet provides coroutine-friendly versions of stdlib and few other packages under `eventlet.green`. Green `select` used to have `poll` just imported from stdlib, not coroutine-friendly, means `eventlet.green.select.poll.poll().poll()` will block everything. Which is clearly not "green", so it was removed with best intentions.

You can still have poll by using: `poll = eventlet.patcher.original('select').poll` but remember, it will block every other greenthread, like unpatched `time.sleep` or file IO backed by dying HDD. `patcher.original` returns same module object as import in vanilla Python stdlib without eventlet.

With that please try to offload poll it to thread pool, using `eventlet.tpool.Proxy(pollobj)` or `eventlet.tpool.execute(pollobj.poll)`.

If threadpool doesn't work, your next best solution running poll with small timeout interleaved by `eventlet.sleep()` to give other greenthreads chance to run, like so

```diff
-from select import poll
+poll = eventlet.patcher.original('select').poll
pollobj = poll.poll()
...
- pollobj.poll()
+ while not pollobj.poll(timeout=0.02):  # mean 10ms, max 20ms lag on all other operations
    eventlet.sleep()
```

Fly safe.
@temoto Thanks for a heads up - will look into it next week.

The main problem was that we don't directly use the removed functionality ourselves, but it's a 3rd party library, so I need to figure out some work around.

The good thing is that in the context we use that library (inside an isolated and short lived subprocess) blocking is not a big deal so maybe I will just try that.

Resolving patch:
diff --git a/st2common/st2common/util/monkey_patch.py b/st2common/st2common/util/monkey_patch.py
--- a/st2common/st2common/util/monkey_patch.py
+++ b/st2common/st2common/util/monkey_patch.py
@@ -23,6 +23,7 @@
 
 __all__ = [
     'monkey_patch',
+    'use_select_poll_workaround',
     'is_use_debugger_flag_provided'
 ]
 
@@ -44,6 +45,21 @@ def monkey_patch():
     eventlet.monkey_patch(os=True, select=True, socket=True, thread=patch_thread, time=True)
 
 
+def use_select_poll_workaround():
+    """
+    Work around for some tests which injects original select module with select.poll()
+    available to sys.modules.
+    """
+    import sys
+    import subprocess
+    import eventlet
+
+    # Work around to get tests to pass with eventlet >= 0.20.0
+    if 'nose' in sys.modules.keys():
+        sys.modules['select'] = eventlet.patcher.original('select')
+        subprocess.select = eventlet.patcher.original('select')
+
+
 def is_use_debugger_flag_provided():
     # 1. Check sys.argv directly
     if USE_DEBUGGER_FLAG in sys.argv:


Test patch:
diff --git a/contrib/packs/tests/test_action_download.py b/contrib/packs/tests/test_action_download.py
--- a/contrib/packs/tests/test_action_download.py
+++ b/contrib/packs/tests/test_action_download.py
@@ -21,6 +21,9 @@
 import tempfile
 import hashlib
 
+from st2common.util.monkey_patch import use_select_poll_workaround
+use_select_poll_workaround()
+
 from lockfile import LockFile
 from lockfile import LockTimeout
 from git.repo import Repo
diff --git a/contrib/packs/tests/test_action_unload.py b/contrib/packs/tests/test_action_unload.py
--- a/contrib/packs/tests/test_action_unload.py
+++ b/contrib/packs/tests/test_action_unload.py
@@ -19,6 +19,9 @@
 
 from oslo_config import cfg
 
+from st2common.util.monkey_patch import use_select_poll_workaround
+use_select_poll_workaround()
+
 from st2common.content.bootstrap import register_content
 from st2common.persistence.pack import Pack
 from st2common.persistence.pack import Config
diff --git a/st2common/tests/unit/test_pack_management.py b/st2common/tests/unit/test_pack_management.py
--- a/st2common/tests/unit/test_pack_management.py
+++ b/st2common/tests/unit/test_pack_management.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 
 from __future__ import absolute_import
+
 import os
 import sys
 
@@ -25,8 +26,15 @@
 
 sys.path.insert(0, PACK_ACTIONS_DIR)
 
+from st2common.util.monkey_patch import use_select_poll_workaround
+use_select_poll_workaround()
+
 from pack_mgmt.download import DownloadGitRepoAction
 
+__all__ = [
+    'InstallPackTestCase'
+]
+
 
 class InstallPackTestCase(unittest2.TestCase):