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
pull/72904/head
Alexei Znamensky 4 years ago committed by GitHub
parent 7f1ee07634
commit 71ef981191
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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).

@ -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)

@ -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:
cwd = to_bytes(os.path.abspath(os.path.expanduser(cwd)), errors='surrogate_or_strict') if os.path.isdir(cwd):
kwargs['cwd'] = cwd cwd = to_bytes(os.path.abspath(os.path.expanduser(cwd)), errors='surrogate_or_strict')
try: kwargs['cwd'] = cwd
os.chdir(cwd) try:
except (OSError, IOError) as e: os.chdir(cwd)
self.fail_json(rc=e.errno, msg="Could not open %s, %s" % (cwd, to_native(e)), except (OSError, IOError) as e:
exception=traceback.format_exc()) self.fail_json(rc=e.errno, msg="Could not chdir to %s, %s" % (cwd, to_native(e)),
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:

@ -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'])

Loading…
Cancel
Save