synchronize - fix password authentication (#66542)

On Python 2, leave all fds open since there is no mechanism to close specific fds with subprocess.Popen() on Python 2

Add unit tests.

Co-authored-by: Matt Martz <matt@sivel.net>
This commit is contained in:
Sam Doran 2020-01-21 10:43:56 -05:00 committed by GitHub
parent 986c9cf6a1
commit 617fbad743
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 2 deletions

View file

@ -0,0 +1,6 @@
bugfixes:
- synchronize - fix password authentication on Python 2 (https://github.com/ansible/ansible/issues/56629)
- >
AnsibleModule.run_command() - set ``close_fds`` to ``False`` on Python 2 if ``pass_fds`` are passed to
``run_command()``. Since ``subprocess.Popen()`` on Python 2 does not have the ``pass_fds`` option,
there is no way to exclude a specific list of file descriptors from being closed.

View file

@ -2452,9 +2452,10 @@ class AnsibleModule(object):
are expanded before running the command. When ``True`` a string such as
``$SHELL`` will be expanded regardless of escaping. When ``False`` and
``use_unsafe_shell=False`` no path or variable expansion will be done.
:kw pass_fds: When running on python3 this argument
:kw pass_fds: When running on Python 3 this argument
dictates which file descriptors should be passed
to an underlying ``Popen`` constructor.
to an underlying ``Popen`` constructor. On Python 2, this will
set ``close_fds`` to False.
:kw before_communicate_callback: This function will be called
after ``Popen`` object will be created
but before communicating to the process.
@ -2565,6 +2566,8 @@ class AnsibleModule(object):
)
if PY3 and pass_fds:
kwargs["pass_fds"] = pass_fds
elif PY2 and pass_fds:
kwargs['close_fds'] = False
# store the pwd
prev_dir = os.getcwd()

View file

@ -13,6 +13,7 @@ from io import BytesIO
import pytest
from ansible.module_utils._text import to_native
from ansible.module_utils.six import PY2
class OpenBytesIO(BytesIO):
@ -197,3 +198,22 @@ class TestRunCommandOutput:
# bytes because it's returning native strings
assert stdout == to_native(u'Žarn§')
assert stderr == to_native(u'لرئيسية')
@pytest.mark.parametrize('stdin', [{}], indirect=['stdin'])
def test_run_command_fds(mocker, rc_am):
subprocess_mock = mocker.patch('ansible.module_utils.basic.subprocess')
subprocess_mock.Popen.side_effect = AssertionError
try:
rc_am.run_command('synchronize', pass_fds=(101, 42))
except SystemExit:
pass
if PY2:
assert subprocess_mock.Popen.call_args[1]['close_fds'] is False
assert 'pass_fds' not in subprocess_mock.Popen.call_args[1]
else:
assert subprocess_mock.Popen.call_args[1]['pass_fds'] == (101, 42)
assert subprocess_mock.Popen.call_args[1]['close_fds'] is True