1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Fix the local and ssh plugins for a cornercase retrying a syscall

The bundled selectors library which is used by the local and ssh
connection plugins had a bug which caused a traceback in a cornercase.
If selectors were in use and a syscall was interrupted, selectors would
attempt to restart the syscall after the interrupt was processed.  if
the attempt determined that the timeout for running the syscall had
already expired, the code attempted to raise OSError.  The raise was
using a Python3-ism and needed to be ported to work on Python2.

Fixes #41630
This commit is contained in:
Toshio Kuratomi 2018-08-09 21:01:27 -07:00
parent 1fb0e11b56
commit e2e44f846c
3 changed files with 24 additions and 8 deletions

View file

@ -0,0 +1,5 @@
---
bugfixes:
- fix for the bundled selectors module (used in the ssh and local connection
plugins) when a syscall is restarted after being interrupted by a signal
(https://github.com/ansible/ansible/issues/41630)

View file

@ -25,6 +25,14 @@ package exists on pypi to backport the functionality as far as python-2.6.
''' '''
# The following makes it easier for us to script updates of the bundled code # The following makes it easier for us to script updates of the bundled code
_BUNDLED_METADATA = {"pypi_name": "selectors2", "version": "1.1.0"} _BUNDLED_METADATA = {"pypi_name": "selectors2", "version": "1.1.0"}
# Added these bugfix commits from 2.1.0:
# * https://github.com/SethMichaelLarson/selectors2/commit/3bd74f2033363b606e1e849528ccaa76f5067590
# Wrap kqueue.control so that timeout is a keyword arg
# * https://github.com/SethMichaelLarson/selectors2/commit/6f6a26f42086d8aab273b30be492beecb373646b
# Fix formatting of the kqueue.control patch for pylint
# * https://github.com/SethMichaelLarson/selectors2/commit/f0c2c6c66cfa7662bc52beaf4e2d65adfa25e189
# Fix use of OSError exception for py3 and use the wrapper of kqueue.control so retries of
# interrupted syscalls work with kqueue
import os.path import os.path
import sys import sys

View file

@ -137,7 +137,7 @@ else:
if expires is not None: if expires is not None:
current_time = monotonic() current_time = monotonic()
if current_time > expires: if current_time > expires:
raise OSError(errno=errno.ETIMEDOUT) raise OSError(errno.ETIMEDOUT)
if recalc_timeout: if recalc_timeout:
if "timeout" in kwargs: if "timeout" in kwargs:
kwargs["timeout"] = expires - current_time kwargs["timeout"] = expires - current_time
@ -342,7 +342,7 @@ if hasattr(select, "select"):
timeout = None if timeout is None else max(timeout, 0.0) timeout = None if timeout is None else max(timeout, 0.0)
ready = [] ready = []
r, w, _ = _syscall_wrapper(self._select, True, self._readers, r, w, _ = _syscall_wrapper(self._select, True, self._readers,
self._writers, timeout) self._writers, timeout=timeout)
r = set(r) r = set(r)
w = set(w) w = set(w)
for fd in r | w: for fd in r | w:
@ -563,14 +563,14 @@ if hasattr(select, "kqueue"):
select.KQ_FILTER_READ, select.KQ_FILTER_READ,
select.KQ_EV_ADD) select.KQ_EV_ADD)
_syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0)
if events & EVENT_WRITE: if events & EVENT_WRITE:
kevent = select.kevent(key.fd, kevent = select.kevent(key.fd,
select.KQ_FILTER_WRITE, select.KQ_FILTER_WRITE,
select.KQ_EV_ADD) select.KQ_EV_ADD)
_syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0)
return key return key
@ -581,7 +581,7 @@ if hasattr(select, "kqueue"):
select.KQ_FILTER_READ, select.KQ_FILTER_READ,
select.KQ_EV_DELETE) select.KQ_EV_DELETE)
try: try:
_syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0)
except SelectorError: except SelectorError:
pass pass
if key.events & EVENT_WRITE: if key.events & EVENT_WRITE:
@ -589,7 +589,7 @@ if hasattr(select, "kqueue"):
select.KQ_FILTER_WRITE, select.KQ_FILTER_WRITE,
select.KQ_EV_DELETE) select.KQ_EV_DELETE)
try: try:
_syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0)
except SelectorError: except SelectorError:
pass pass
@ -602,8 +602,8 @@ if hasattr(select, "kqueue"):
max_events = len(self._fd_to_key) * 2 max_events = len(self._fd_to_key) * 2
ready_fds = {} ready_fds = {}
kevent_list = _syscall_wrapper(self._kqueue.control, True, kevent_list = _syscall_wrapper(self._wrap_control, True,
None, max_events, timeout) None, max_events, timeout=timeout)
for kevent in kevent_list: for kevent in kevent_list:
fd = kevent.ident fd = kevent.ident
@ -628,6 +628,9 @@ if hasattr(select, "kqueue"):
self._kqueue.close() self._kqueue.close()
super(KqueueSelector, self).close() super(KqueueSelector, self).close()
def _wrap_control(self, changelist, max_events, timeout):
return self._kqueue.control(changelist, max_events, timeout)
__all__.append('KqueueSelector') __all__.append('KqueueSelector')