Backport/2.10/72390 (#72690)

* Return error if cwd directory does not exist (#72390)

* Return warning or error if cwd directory does not exist, in AnsibleModule.run_command()

(cherry picked from commit 5654de6fce)

* added flag in run_command signature to control behaviour when cwd does not exist
This commit is contained in:
Alexei Znamensky 2020-12-08 13:07:29 +13:00 committed by GitHub
parent 7f1ee07634
commit 71ef981191
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 9 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- basic.AnsibleModule - AnsibleModule.run_command silently ignores a non-existent directory in the ``cwd`` argument (https://github.com/ansible/ansible/pull/72390).

View file

@ -0,0 +1,2 @@
bugfixes:
- AnsibleModule - added arg ``ignore_invalid_cwd`` to ``AnsibleModule.run_command()``, to control its behaviour when ``cwd`` is invalid. (https://github.com/ansible/ansible/pull/72390)

View file

@ -2531,7 +2531,7 @@ class AnsibleModule(object):
def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None,
use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict', use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict',
expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None): expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None, ignore_invalid_cwd=True):
''' '''
Execute a command, returns rc, stdout, and stderr. Execute a command, returns rc, stdout, and stderr.
@ -2582,6 +2582,9 @@ class AnsibleModule(object):
after ``Popen`` object will be created after ``Popen`` object will be created
but before communicating to the process. but before communicating to the process.
(``Popen`` object will be passed to callback as a first argument) (``Popen`` object will be passed to callback as a first argument)
:kw ignore_invalid_cwd: This flag indicates whether an invalid ``cwd``
(non-existent or not a directory) should be ignored or should raise
an exception.
:returns: A 3-tuple of return code (integer), stdout (native string), :returns: A 3-tuple of return code (integer), stdout (native string),
and stderr (native string). On python2, stdout and stderr are both and stderr (native string). On python2, stdout and stderr are both
byte strings. On python3, stdout and stderr are text strings converted byte strings. On python3, stdout and stderr are text strings converted
@ -2695,14 +2698,17 @@ class AnsibleModule(object):
prev_dir = os.getcwd() prev_dir = os.getcwd()
# make sure we're in the right working directory # make sure we're in the right working directory
if cwd and os.path.isdir(cwd): if cwd:
if os.path.isdir(cwd):
cwd = to_bytes(os.path.abspath(os.path.expanduser(cwd)), errors='surrogate_or_strict') cwd = to_bytes(os.path.abspath(os.path.expanduser(cwd)), errors='surrogate_or_strict')
kwargs['cwd'] = cwd kwargs['cwd'] = cwd
try: try:
os.chdir(cwd) os.chdir(cwd)
except (OSError, IOError) as e: except (OSError, IOError) as e:
self.fail_json(rc=e.errno, msg="Could not open %s, %s" % (cwd, to_native(e)), self.fail_json(rc=e.errno, msg="Could not chdir to %s, %s" % (cwd, to_native(e)),
exception=traceback.format_exc()) exception=traceback.format_exc())
elif not ignore_invalid_cwd:
self.fail_json(msg="Provided cwd is not a valid directory: %s" % cwd)
old_umask = None old_umask = None
if umask: if umask:

View file

@ -180,6 +180,14 @@ class TestRunCommandCwd:
rc_am.run_command('/bin/ls', cwd='/not-a-dir') rc_am.run_command('/bin/ls', cwd='/not-a-dir')
assert rc_am._os.chdir.mock_calls == [mocker.call('/old'), ] assert rc_am._os.chdir.mock_calls == [mocker.call('/old'), ]
@pytest.mark.parametrize('stdin', [{}], indirect=['stdin'])
def test_cwd_not_a_dir_noignore(self, rc_am):
rc_am._os.getcwd.return_value = '/old'
rc_am._os.path.isdir.side_effect = lambda d: d != '/not-a-dir'
with pytest.raises(SystemExit):
rc_am.run_command('/bin/ls', cwd='/not-a-dir', ignore_invalid_cwd=False)
assert rc_am.fail_json.called
class TestRunCommandPrompt: class TestRunCommandPrompt:
@pytest.mark.parametrize('stdin', [{}], indirect=['stdin']) @pytest.mark.parametrize('stdin', [{}], indirect=['stdin'])