community.general/lib/ansible
Abhijit Menon-Sen 6e82df451a Clarify select() handling for ssh connections
This change is motivated by an ssh oddity: when ControlPersist is
enabled, the first (i.e. master) connection goes into the background; we
see EOF on its stdout and the process exits, but we never see EOF on its
stderr. So if we ran a command like this:

    ANSIBLE_SSH_PIPELINING=1 ansible -T 30 -vvv somehost -u someuser -m command -a whoami

We would first do select([stdout,stderr], timeout) and read the command
module output, then select([stdout,stderr], timeout) again and read EOF
on stdout, then select([stderr], timeout) AGAIN (though the process has
exited), and select() would wait for the full timeout before returning
rfd=[], and then we would exit. The use of a very short timeout in the
code masked the underlying problem (that we don't see EOF on stderr).

It's always preferable to call select() with a long timeout so that the
process doesn't use any CPU until one of the events it's interested in
happens (and then select will return independent of elapsed time).

(A long timeout value means "if nothing happens, sleep for up to <x>";
omitting the timeout value means "if nothing happens, sleep forever";
specifying a zero timeout means "don't sleep at all", i.e. poll for
events and return immediately.)

This commit uses a long timeout, but explicitly detects the condition
where we've seen EOF on stdout and the process has exited, but we have
not seen EOF on stderr. If and only if that happens, it reruns select()
with a short timeout (in practice it could just exit at that point, but
I chose to be extra cautious). As a result, we end up calling select()
far less often, and use less CPU while waiting, but don't sleep for a
long time waiting for something that will never happen.

Note that we don't omit the timeout to select() altogether because if
we're waiting for an escalation prompt, we DO want to give up with an
error after some time. We also don't set exceptfds, because we're not
actually acting on any notifications of exceptional conditions.
2015-09-24 12:10:16 -04:00
..
cli Apply --limit to inventory in adhoc commands 2015-09-23 08:28:38 -04:00
compat Making the switch to v2 2015-05-03 21:47:26 -05:00
config Making the switch to v2 2015-05-03 21:47:26 -05:00
errors Making the switch to v2 2015-05-03 21:47:26 -05:00
executor correct typo on error reporting 2015-09-23 10:11:52 -04:00
galaxy Fix typo in ansible module_utils import from galaxy code 2015-09-17 14:25:48 -04:00
inventory Python 3: there's no basestring 2015-09-23 10:04:26 +03:00
module_utils Add Weekday (0-6) as a number and add weeknumber (00-52) 2015-09-24 15:05:44 +02:00
modules Update extras submodule ref 2015-09-24 07:18:23 -07:00
new_inventory Making the switch to v2 2015-05-03 21:47:26 -05:00
parsing Python 3: there's no basestring 2015-09-22 08:42:33 +03:00
playbook Improve error catching from malformed playbook data 2015-09-23 08:56:36 -04:00
plugins Clarify select() handling for ssh connections 2015-09-24 12:10:16 -04:00
template Fix safe_eval() of set literals 2015-09-11 09:41:05 +03:00
utils Remove custom json encoder cleaner and strip proxy var stuff out before encoding 2015-09-17 16:04:47 -04:00
vars Remove unnecessary calls to save inventory restrictions since 81bf88b 2015-09-23 12:18:09 -04:00
__init__.py Re-adding submodules after moving things around 2015-05-03 22:30:51 -05:00
constants.py Implement ssh connection handling as a state machine 2015-09-23 01:55:00 -04:00
test-requirements.txt Making the switch to v2 2015-05-03 21:47:26 -05:00